Skip to content

Commit b47a971

Browse files
Merge pull request #625 from dfinity/unity-ii-improvement
Improve Unity ii integration samples.
2 parents abf2568 + 5ce9af2 commit b47a971

File tree

60 files changed

+446
-385
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+446
-385
lines changed

native-apps/unity_ii_applink/README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,22 @@ This is a Unity project with [ICP.NET](https://github.com/BoomDAO/ICP.NET) embed
1111
## Workflow
1212
Before continuing, please read through the [Android App Links](https://developer.android.com/studio/write/app-link-indexing) to understand how Android App Links works.
1313

14-
Here is the basic workflow that how to integrate with Internet Identity from a Unity Android game. The basic idea is to open the Web Browser from the game, login in with II in the browser, and pass the DelegationIdentity back to the game.
14+
Here is the basic workflow that how to integrate with Internet Identity from a Unity Android game. The basic idea is to open the Web Browser from the game, login in with II in the browser, and pass the `DelegationChain` back to the game.
1515

1616
The steps in detail are described below:
1717

1818
1. Set up an [Internet Identity integration dapp](#ii_integration_dapp) which supports logging in with II, with an `assetlinks.json` file associated.
1919
Please refer to [ii_integration_dapp](./ii_integration_dapp/README.md) to set up the dapp.
20+
2021
2. Run a Unity game on Android, which is built from [android_integration sample](#unity_project).
2122
Please refer to [unity_project](./unity_project/README.md) to build the Unity Android game.
23+
2224
3. Launch the Web Browser from the game to open the dapp frontend deployed in #1, with the public key of `Ed25519Identity` as a parameter.
25+
2326
4. Login with your Internet Identity in the Web Browser.
24-
5. Launch the application via App Links, and pass the `DelegationIdentity` back to the game as the URL parameter.
25-
6. Call the backend canister with the `DelegationIdentity` to greet.
27+
28+
5. Launch the application via App Links, and pass the `DelegationChain` back to the game as the URL parameter.
29+
30+
6. Composite the `DelegationIdentity` with `DelegationChain` and the `Ed25519Identity`.
31+
32+
7. Call the backend canister with the `DelegationIdentity` to greet.

native-apps/unity_ii_applink/ii_integration_dapp/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,15 @@ This example derives from the [internet_identity_integration](https://github.com
44

55
## Overview
66

7-
This example shows a special case to support login with the `IncompleteEd25519KeyIdentity` which only contains the public key. The reason why we support this is all for security.
7+
This example shows a use case to support login with the two delegations on the `DelegationChain`.
88

99
As we described in [Internet Identity Integration](../README.md#workflow), users can log in with II from the game. Usually what they do is
1010

1111
1. Generate the `Ed25519KeyIdentity` supported by [ICP.NET](https://github.com/BoomDAO/ICP.NET) in the Unity game.
12-
2. For security purposes, only pass the public key of the `Ed25519KeyIdentity` to the Web browser for login, this is where `IncompleteEd25519KeyIdentity` can be used for.
13-
3. In [index.js](./src/greet_frontend/src/index.js), we describe how to retrieve the public key of the `Ed25519Identity` from the URL parameter, use it to instantiate an `IncompleteEd25519KeyIdentity`, and log in with Internet Identity.
12+
2. For security purposes, only pass the public key of the `Ed25519KeyIdentity` to the Web browser for login. And only the public key is necessary when creating a `DelegationChain`.
13+
3. In [index.js](./src/greet_frontend/src/index.js), we describe how to
14+
- log in with Internet Identity with the frontend generated session key
15+
- retrieve the public key of the `Ed25519Identity` from the URL parameter and create another delegation with it.
1416

1517
With this, users don't need to pass the private key around, also they don't need to store the private key outside of the game as they can regenerate the key pairs for every session.
1618

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"greet_backend": {
3+
"ic": "72rj2-biaaa-aaaan-qdatq-cai"
4+
},
5+
"greet_frontend": {
6+
"ic": "6x7nu-oaaaa-aaaan-qdaua-cai"
7+
}
8+
}

native-apps/unity_ii_applink/ii_integration_dapp/src/greet_frontend/assets/.well-known/assetlinks.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@
22
"relation": ["delegate_permission/common.handle_all_urls"],
33
"target": {
44
"namespace": "android_app",
5-
"package_name": "com.DefaultCompany.II_AppLink_Integration",
5+
"package_name": "com.dfinity.ii_applink_integration",
66
"sha256_cert_fingerprints":
7-
["86:C9:CA:6F:5A:53:7E:75:9C:D7:29:1E:8A:94:90:BE:90:0B:02:12:40:45:19:B6:65:84:3C:02:AB:B5:97:14"]
7+
["A3:E2:36:BC:E9:04:3F:8F:A9:C5:9B:B5:FE:89:95:C8:08:BA:35:2D:07:D8:76:13:65:A9:27:D6:33:6B:44:6E"]
88
}
99
}]

native-apps/unity_ii_applink/ii_integration_dapp/src/greet_frontend/src/index.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
<button id="open">Launch Application by AppLink</button>
2222
</form>
2323
<br />
24+
<form>
25+
<button id="greet">Greet</button>
26+
</form>
27+
<section id="greeting"></section>
2428
</main>
2529
</body>
2630
</html>
Lines changed: 56 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,47 +1,30 @@
1-
import {AuthClient} from "@dfinity/auth-client"
2-
import {SignIdentity} from "@dfinity/agent";
3-
import {DelegationIdentity, Ed25519PublicKey } from "@dfinity/identity";
4-
5-
// An incomplete Ed25519KeyIdentity with only the public key provided.
6-
class IncompleteEd25519KeyIdentity extends SignIdentity {
7-
constructor(publicKey) {
8-
super();
9-
this._publicKey = publicKey;
10-
}
11-
12-
getPublicKey () {
13-
return this._publicKey;
14-
}
15-
}
16-
17-
function fromHexString(hexString) {
18-
return new Uint8Array((hexString.match(/.{1,2}/g) ?? []).map(byte => parseInt(byte, 16))).buffer;
19-
}
1+
import {createActor, greet_backend} from "../../declarations/greet_backend";
2+
import {AuthClient} from "@dfinity/auth-client";
3+
import {HttpAgent} from "@dfinity/agent";
4+
import {DelegationIdentity, Ed25519PublicKey, ECDSAKeyIdentity, DelegationChain} from "@dfinity/identity";
5+
import {fromHexString} from "@dfinity/identity/lib/cjs/buffer";
206

21-
let myKeyIdentity;
22-
let sessionKeyIndex = -1;
7+
let appPublicKey;
238

249
var url = window.location.href;
25-
sessionKeyIndex = url.indexOf("sessionkey=");
26-
if (sessionKeyIndex !== -1) {
27-
// Parse the public session key and instantiate an IncompleteEd25519KeyIdentity.
28-
var sessionkey = url.substring(sessionKeyIndex + "sessionkey=".length);
29-
30-
var publicKey = Ed25519PublicKey.fromDer(fromHexString(sessionkey));
31-
myKeyIdentity = new IncompleteEd25519KeyIdentity(publicKey);
32-
} else {
33-
// TODO: initialize an Ed25519KeyIdentity();
10+
var publicKeyIndex = url.indexOf("sessionkey=");
11+
if (publicKeyIndex !== -1) {
12+
// Parse the public key.
13+
var publicKeyString = url.substring(publicKeyIndex + "sessionkey=".length);
14+
appPublicKey = Ed25519PublicKey.fromDer(fromHexString(publicKeyString));
3415
}
3516

36-
let delegationIdentity;
17+
let actor = greet_backend;
18+
let delegationChain;
3719

3820
const loginButton = document.getElementById("login");
3921
loginButton.onclick = async (e) => {
4022
e.preventDefault();
4123

4224
// Create an auth client.
25+
var middleKeyIdentity = await ECDSAKeyIdentity.generate();
4326
let authClient = await AuthClient.create({
44-
identity: myKeyIdentity,
27+
identity: middleKeyIdentity,
4528
});
4629

4730
// Start the login process and wait for it to finish.
@@ -53,9 +36,24 @@ loginButton.onclick = async (e) => {
5336
});
5437

5538
// At this point we're authenticated, and we can get the identity from the auth client.
56-
const identity = authClient.getIdentity();
57-
if (identity instanceof DelegationIdentity) {
58-
delegationIdentity = identity;
39+
const middleIdentity = authClient.getIdentity();
40+
41+
// Using the identity obtained from the auth client to create an agent to interact with the IC.
42+
const agent = new HttpAgent({identity: middleIdentity});
43+
actor = createActor(process.env.GREET_BACKEND_CANISTER_ID, {
44+
agent,
45+
});
46+
47+
// Create another delegation with the app public key, then we have two delegations on the chain.
48+
if (appPublicKey != null && middleIdentity instanceof DelegationIdentity ) {
49+
let middleToApp = await DelegationChain.create(
50+
middleKeyIdentity,
51+
appPublicKey,
52+
new Date(Date.now() + 15 * 60 * 1000),
53+
{ previous: middleIdentity.getDelegation() },
54+
);
55+
56+
delegationChain = middleToApp;
5957
}
6058

6159
return false;
@@ -65,19 +63,33 @@ const openButton = document.getElementById("open");
6563
openButton.onclick = async (e) => {
6664
e.preventDefault();
6765

68-
// if (sessionKeyIndex === -1) {
69-
// // TODO: warning for not login from a game.
70-
// return false;
71-
// }
66+
if (delegationChain == null){
67+
console.log("Invalid delegation chain.");
68+
return false;
69+
}
7270

7371
var url = "https://6x7nu-oaaaa-aaaan-qdaua-cai.icp0.io/authorize?";
74-
if (delegationIdentity != null) {
75-
var delegationString = JSON.stringify(delegationIdentity.getDelegation().toJSON());
76-
console.log(delegationString);
77-
url = url + "delegation=" + encodeURIComponent(delegationString);
78-
}
72+
var delegationString = JSON.stringify(delegationChain.toJSON());
73+
url = url + "delegation=" + encodeURIComponent(delegationString);
74+
//console.log(url);
7975

8076
window.open(url, "_self");
8177

8278
return false;
8379
};
80+
81+
const greetButton = document.getElementById("greet");
82+
greetButton.onclick = async (e) => {
83+
e.preventDefault();
84+
85+
greetButton.setAttribute("disabled", true);
86+
87+
// Interact with backend actor, calling the greet method
88+
const greeting = await actor.greet();
89+
90+
greetButton.removeAttribute("disabled");
91+
92+
document.getElementById("greeting").innerText = greeting;
93+
94+
return false;
95+
};

native-apps/unity_ii_deeplink/unity_project/Assets/ICP.NET/Chaos.NaCl.dll.meta renamed to native-apps/unity_ii_applink/unity_project/Assets/ICP.NET/BouncyCastle.Cryptography.dll.meta

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)