From 3a7baf26ee0d9ef6644344c01493a5c85b9a13e8 Mon Sep 17 00:00:00 2001 From: Franz-Stefan Preiss Date: Tue, 1 Oct 2024 17:22:07 +0200 Subject: [PATCH] Fix Internet Identity integration in vetKD examples and make them work in Safari (#1007) --- motoko/vetkd/src/app_backend/Main.mo | 6 +++--- .../src/app_frontend_js/assets/.ic-assets.json5 | 2 +- .../src/app_frontend_js/src/.ic-assets.json5 | 2 +- motoko/vetkd/src/app_frontend_js/src/index.js | 16 ++++++++++++++-- .../src/app_frontend_js/assets/.ic-assets.json5 | 2 +- .../src/app_frontend_js/src/.ic-assets.json5 | 2 +- rust/vetkd/src/app_frontend_js/src/index.js | 16 ++++++++++++++-- 7 files changed, 35 insertions(+), 11 deletions(-) diff --git a/motoko/vetkd/src/app_backend/Main.mo b/motoko/vetkd/src/app_backend/Main.mo index 83f6b8f9b..91a3a3e1c 100644 --- a/motoko/vetkd/src/app_backend/Main.mo +++ b/motoko/vetkd/src/app_backend/Main.mo @@ -22,7 +22,7 @@ actor { let vetkd_system_api : VETKD_SYSTEM_API = actor ("s55qq-oqaaa-aaaaa-aaakq-cai"); - public shared ({ caller }) func app_vetkd_public_key(derivation_path : [Blob]) : async Text { + public shared ({ caller = _ }) func app_vetkd_public_key(derivation_path : [Blob]) : async Text { let { public_key } = await vetkd_system_api.vetkd_public_key({ canister_id = null; derivation_path; @@ -31,7 +31,7 @@ actor { Hex.encode(Blob.toArray(public_key)); }; - public shared ({ caller }) func symmetric_key_verification_key() : async Text { + public shared ({ caller = _ }) func symmetric_key_verification_key() : async Text { let { public_key } = await vetkd_system_api.vetkd_public_key({ canister_id = null; derivation_path = Array.make(Text.encodeUtf8("symmetric_key")); @@ -52,7 +52,7 @@ actor { Hex.encode(Blob.toArray(encrypted_key)); }; - public shared ({ caller }) func ibe_encryption_key() : async Text { + public shared ({ caller = _ }) func ibe_encryption_key() : async Text { let { public_key } = await vetkd_system_api.vetkd_public_key({ canister_id = null; derivation_path = Array.make(Text.encodeUtf8("ibe_encryption")); diff --git a/motoko/vetkd/src/app_frontend_js/assets/.ic-assets.json5 b/motoko/vetkd/src/app_frontend_js/assets/.ic-assets.json5 index 8dc76d1ee..8ad98ac6a 100644 --- a/motoko/vetkd/src/app_frontend_js/assets/.ic-assets.json5 +++ b/motoko/vetkd/src/app_frontend_js/assets/.ic-assets.json5 @@ -24,7 +24,7 @@ // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. // - We added img-src data: because data: images are used often. // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. - "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';", // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. // To configure permissions go here https://www.permissionspolicy.com/ diff --git a/motoko/vetkd/src/app_frontend_js/src/.ic-assets.json5 b/motoko/vetkd/src/app_frontend_js/src/.ic-assets.json5 index 8dc76d1ee..8ad98ac6a 100644 --- a/motoko/vetkd/src/app_frontend_js/src/.ic-assets.json5 +++ b/motoko/vetkd/src/app_frontend_js/src/.ic-assets.json5 @@ -24,7 +24,7 @@ // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. // - We added img-src data: because data: images are used often. // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. - "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';", // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. // To configure permissions go here https://www.permissionspolicy.com/ diff --git a/motoko/vetkd/src/app_frontend_js/src/index.js b/motoko/vetkd/src/app_frontend_js/src/index.js index ce8cab512..a2a6869dc 100644 --- a/motoko/vetkd/src/app_frontend_js/src/index.js +++ b/motoko/vetkd/src/app_frontend_js/src/index.js @@ -235,10 +235,22 @@ async function ibe_decrypt(ibe_ciphertext_hex) { document.getElementById("login").onclick = async (e) => { e.preventDefault(); + + // According to https://github.com/dfinity/internet-identity?tab=readme-ov-file#local-replica, + // for local deployments, the II URL must be different depending on the browser: + // Chrome, Firefox: http://.localhost:4943 + // Safari: http://localhost:4943?canisterId= + // + // Safari detection rules are according to: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#browser_name_and_version + let isSafari = /^(?!.*chrome\/\d+)(?!.*chromium\/\d+).*safari\/\d+/i.test(navigator.userAgent); + let identityProvider = isSafari ? + `http://localhost:4943/?canisterId=${process.env.CANISTER_ID_INTERNET_IDENTITY}` : + `http://${process.env.CANISTER_ID_INTERNET_IDENTITY}.localhost:4943/`; + let authClient = await AuthClient.create(); await new Promise((resolve) => { authClient.login({ - identityProvider: `http://127.0.0.1:4943/?canisterId=${process.env.INTERNET_IDENTITY_CANISTER_ID}`, + identityProvider: identityProvider, onSuccess: resolve, }); }); @@ -247,7 +259,7 @@ document.getElementById("login").onclick = async (e) => { // Using the identity obtained from the auth client, we can create an agent to interact with the IC. const agent = new HttpAgent({ identity }); // Using the interface description of our webapp, we create an actor that we use to call the service methods. We override the global actor, such that the other button handler will automatically use the new actor with the Internet Identity provided delegation. - app_backend_actor = createActor(process.env.APP_BACKEND_CANISTER_ID, { + app_backend_actor = createActor(process.env.CANISTER_ID_APP_BACKEND, { agent, }); app_backend_principal = identity.getPrincipal(); diff --git a/rust/vetkd/src/app_frontend_js/assets/.ic-assets.json5 b/rust/vetkd/src/app_frontend_js/assets/.ic-assets.json5 index 8dc76d1ee..8ad98ac6a 100644 --- a/rust/vetkd/src/app_frontend_js/assets/.ic-assets.json5 +++ b/rust/vetkd/src/app_frontend_js/assets/.ic-assets.json5 @@ -24,7 +24,7 @@ // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. // - We added img-src data: because data: images are used often. // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. - "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';", // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. // To configure permissions go here https://www.permissionspolicy.com/ diff --git a/rust/vetkd/src/app_frontend_js/src/.ic-assets.json5 b/rust/vetkd/src/app_frontend_js/src/.ic-assets.json5 index 8dc76d1ee..8ad98ac6a 100644 --- a/rust/vetkd/src/app_frontend_js/src/.ic-assets.json5 +++ b/rust/vetkd/src/app_frontend_js/src/.ic-assets.json5 @@ -24,7 +24,7 @@ // See: https://github.com/WebAssembly/content-security-policy/blob/main/proposals/CSP.md. // - We added img-src data: because data: images are used often. // - frame-ancestors: none mitigates clickjacking attacks. See https://owasp.org/www-community/attacks/Clickjacking. - "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';upgrade-insecure-requests;", + "Content-Security-Policy": "default-src 'self';script-src 'self' 'unsafe-eval';connect-src 'self' https://icp0.io https://*.icp0.io;img-src 'self' data:;style-src * 'unsafe-inline';style-src-elem * 'unsafe-inline';font-src *;object-src 'none';base-uri 'self';frame-ancestors 'none';form-action 'self';", // Security: The permissions policy disables all features for security reasons. If your site needs such permissions, activate them. // To configure permissions go here https://www.permissionspolicy.com/ diff --git a/rust/vetkd/src/app_frontend_js/src/index.js b/rust/vetkd/src/app_frontend_js/src/index.js index ce8cab512..2c12baf77 100644 --- a/rust/vetkd/src/app_frontend_js/src/index.js +++ b/rust/vetkd/src/app_frontend_js/src/index.js @@ -235,10 +235,22 @@ async function ibe_decrypt(ibe_ciphertext_hex) { document.getElementById("login").onclick = async (e) => { e.preventDefault(); + + // According to https://github.com/dfinity/internet-identity?tab=readme-ov-file#local-replica, + // for local deployments, the II URL must be different depending on the browser: + // Chrome, Firefox: http://.localhost:4943 + // Safari: http://localhost:4943?canisterId= + // + // Safari detection rules are according to: https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent#browser_name_and_version + let isSafari = /^(?!.*chrome\/\d+)(?!.*chromium\/\d+).*safari\/\d+/i.test(navigator.userAgent); + let identityProvider = isSafari ? + `http://127.0.0.1:4943/?canisterId=${process.env.CANISTER_ID_INTERNET_IDENTITY}` : + `http://${process.env.CANISTER_ID_INTERNET_IDENTITY}.localhost:4943/`; + let authClient = await AuthClient.create(); await new Promise((resolve) => { authClient.login({ - identityProvider: `http://127.0.0.1:4943/?canisterId=${process.env.INTERNET_IDENTITY_CANISTER_ID}`, + identityProvider: identityProvider, onSuccess: resolve, }); }); @@ -247,7 +259,7 @@ document.getElementById("login").onclick = async (e) => { // Using the identity obtained from the auth client, we can create an agent to interact with the IC. const agent = new HttpAgent({ identity }); // Using the interface description of our webapp, we create an actor that we use to call the service methods. We override the global actor, such that the other button handler will automatically use the new actor with the Internet Identity provided delegation. - app_backend_actor = createActor(process.env.APP_BACKEND_CANISTER_ID, { + app_backend_actor = createActor(process.env.CANISTER_ID_APP_BACKEND, { agent, }); app_backend_principal = identity.getPrincipal();