Skip to content

Commit

Permalink
Merge pull request #918 from dfinity/kai/auth-client-demo-safari-comp…
Browse files Browse the repository at this point in the history
…atibility

feat: auth client demo safari compatibility
  • Loading branch information
krpeacock authored Jun 20, 2024
2 parents 8fcdec8 + fd69716 commit ed793f9
Show file tree
Hide file tree
Showing 14 changed files with 4,321 additions and 19,086 deletions.
6 changes: 6 additions & 0 deletions motoko/auth_client_demo/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ dfx deps deploy
dfx deploy
```

This will deploy the vanilla JS (using lit-html) version of the application as well as Internet Identity and the `whoami` canister. You can access the canister using the link provided from running `dfx deploy`

Once deployed, start the development server with `npm start`.

You can now access the app at `http://127.0.0.1:5173/`.
Expand All @@ -41,6 +43,10 @@ This demo has multiple versions, each of which demonstrates a different feature
- Vanilla
- Svelte

> Note: the svelte project was created using sveltekit, and has its own `package.json`. Cd into ./src/auth_client_demo_assets/svelte and run `npm install` to run the svelte version.
You can also deploy each of the frontend canisters by editing `package.json` to run the `build:version` script, and `dfx.json` to pull from the `dist` directory of that framework.

## Pulling Internet Identity into your project

To pull Internet Identity into your project, you'll need to do the following:
Expand Down
216 changes: 168 additions & 48 deletions motoko/auth_client_demo/deps/candid/rdmx6-jaaaa-aaaaa-aaadq-cai.did
Original file line number Diff line number Diff line change
Expand Up @@ -171,8 +171,9 @@ type InternetIdentityStats = record {
};
archive_info: ArchiveInfo;
canister_creation_cycles_cost: nat64;
max_num_latest_delegation_origins: nat64;
latest_delegation_origins: vec FrontendHostname
// Map from event aggregation to a sorted list of top 100 sub-keys to their weights.
// Example: {"prepare_delegation_count 24h ic0.app": [{"https://dapp.com", 100}, {"https://dapp2.com", 50}]}
event_aggregations: vec record {text; vec record {text; nat64}};
};

// Configuration parameters related to the archive.
Expand Down Expand Up @@ -227,9 +228,6 @@ type InternetIdentityInit = record {
canister_creation_cycles_cost : opt nat64;
// Rate limit for the `register` call.
register_rate_limit : opt RateLimitConfig;
// Maximum number of latest delegation origins to track.
// Default: 1000
max_num_latest_delegation_origins : opt nat64;
// Maximum number of inflight captchas.
// Default: 500
max_inflight_captchas: opt nat64;
Expand All @@ -241,6 +239,7 @@ type ChallengeResult = record {
key : ChallengeKey;
chars : text;
};
type CaptchaResult = ChallengeResult;

// Extra information about registration status for new devices
type DeviceRegistrationInfo = record {
Expand Down Expand Up @@ -294,6 +293,13 @@ type BufferedArchiveEntry = record {

type IdentityNumber = nat64;

// Map with some variants for the value type.
// Note, due to the Candid mapping this must be a tuple type thus we cannot name the fields `key` and `value`.
type MetadataMapV2 = vec record {
text;
variant { Map : MetadataMapV2; String : text; Bytes : vec nat8 };
};

// Authentication method using WebAuthn signatures
// See https://www.w3.org/TR/webauthn-2/
// This is a separate type because WebAuthn requires to also store
Expand All @@ -312,30 +318,39 @@ type PublicKeyAuthn = record {

// The authentication methods currently supported by II.
type AuthnMethod = variant {
webauthn: WebAuthn;
pubkey: PublicKeyAuthn;
WebAuthn: WebAuthn;
PubKey: PublicKeyAuthn;
};

// This describes whether an authentication method is "protected" or not.
// When protected, a authentication method can only be updated or removed if the
// user is authenticated with that very authentication method.
type AuthnMethodProtection = variant {
protected;
unprotected;
Protected;
Unprotected;
};

type AuthnMethodPurpose = variant {
Recovery;
Authentication;
};

type AuthnMethodSecuritySettings = record {
protection: AuthnMethodProtection;
purpose: AuthnMethodPurpose;
};

type AuthnMethodData = record {
authn_method: AuthnMethod;
protection: AuthnMethodProtection;
purpose: Purpose;
security_settings: AuthnMethodSecuritySettings;
// contains the following fields of the DeviceWithUsage type:
// - alias
// - origin
// - authenticator_attachment: data taken from key_type and reduced to "platform", "cross_platform" or absent on migration
// - usage: data taken from key_type and reduced to "recovery_phrase", "browser_storage_key" or absent on migration
// Note: for compatibility reasons with the v1 API, the entries above (if present)
// must be of the `string` variant. This restriction may be lifted in the future.
metadata: MetadataMap;
// must be of the `String` variant. This restriction may be lifted in the future.
metadata: MetadataMapV2;
last_authentication: opt Timestamp;
};

Expand All @@ -350,28 +365,89 @@ type AuthnMethodRegistrationInfo = record {
expiration: Timestamp;
};

type AuthnMethodConfirmationCode = record {
confirmation_code: text;
expiration: Timestamp;
};

type AuthnMethodRegisterError = variant {
// Authentication method registration mode is off, either due to timeout or because it was never enabled.
RegistrationModeOff;
// There is another authentication method already registered that needs to be confirmed first.
RegistrationAlreadyInProgress;
// The metadata of the provided authentication method contains invalid entries.
InvalidMetadata: text;
};

type AuthnMethodConfirmationError = variant {
// Wrong confirmation code entered. Retry with correct code.
WrongCode: record {
retries_left: nat8
};
// Authentication method registration mode is off, either due to timeout or because it was never enabled.
RegistrationModeOff;
// There is no registered authentication method to be confirmed.
NoAuthnMethodToConfirm;
};

type IdentityAuthnInfo = record {
authn_methods: vec AuthnMethod;
recovery_authn_methods: vec AuthnMethod;
};

type IdentityInfo = record {
authn_methods: vec AuthnMethodData;
authn_method_registration: opt AuthnMethodRegistrationInfo;
// Authentication method independent metadata
metadata: MetadataMap;
metadata: MetadataMapV2;
};

type IdentityInfoError = variant {
/// The principal is not authorized to call this method with the given arguments.
Unauthorized: principal;
/// Internal canister error. See the error message for details.
InternalCanisterError: text;
};

type IdentityInfoResponse = variant {
ok: IdentityInfo;


type IdentityRegisterError = variant {
// No more registrations are possible in this instance of the II service canister.
CanisterFull;
// The captcha check was not successful.
BadCaptcha;
// The metadata of the provided authentication method contains invalid entries.
InvalidMetadata: text;
};

type AuthnMethodAddResponse = variant {
ok;
invalid_metadata: text;
type AuthnMethodAddError = variant {
InvalidMetadata: text;
};

type AuthnMethodRemoveResponse = variant {
ok;
type AuthnMethodReplaceError = variant {
InvalidMetadata: text;
// No authentication method found with the given public key.
AuthnMethodNotFound;
};

type IdentityMetadataReplaceResponse = variant {
ok;
type AuthnMethodMetadataReplaceError = variant {
InvalidMetadata: text;
/// No authentication method found with the given public key.
AuthnMethodNotFound;
};

type AuthnMethodSecuritySettingsReplaceError = variant {
/// No authentication method found with the given public key.
AuthnMethodNotFound;
};

type IdentityMetadataReplaceError = variant {
/// The principal is not authorized to call this method with the given arguments.
Unauthorized: principal;
/// The identity including the new metadata exceeds the maximum allowed size.
StorageSpaceExceeded: record {space_available: nat64; space_required: nat64};
/// Internal canister error. See the error message for details.
InternalCanisterError: text;
};

type PrepareIdAliasRequest = record {
Expand All @@ -383,11 +459,11 @@ type PrepareIdAliasRequest = record {
identity_number : IdentityNumber;
};

type PrepareIdAliasResponse = variant {
/// Credentials prepared successfully, can be retrieved via `get_id_alias`
ok : PreparedIdAlias;
/// Caller authentication failed.
authentication_failed : text;
type PrepareIdAliasError = variant {
/// The principal is not authorized to call this method with the given arguments.
Unauthorized: principal;
/// Internal canister error. See the error message for details.
InternalCanisterError: text;
};

/// The prepared id alias contains two (still unsigned) credentials in JWT format,
Expand All @@ -409,13 +485,13 @@ type GetIdAliasRequest = record {
identity_number : IdentityNumber;
};

type GetIdAliasResponse = variant {
/// The signed id alias credentials
ok : IdAliasCredentials;
/// Caller authentication failed.
authentication_failed : text;
type GetIdAliasError = variant {
/// The principal is not authorized to call this method with the given arguments.
Unauthorized: principal;
/// The credential(s) are not available: may be expired or not prepared yet (call prepare_id_alias to prepare).
no_such_credentials : text;
NoSuchCredentials : text;
/// Internal canister error. See the error message for details.
InternalCanisterError: text;
};

/// The signed id alias credentials for each involved party.
Expand Down Expand Up @@ -460,39 +536,83 @@ service : (opt InternetIdentityInit) -> {
http_request_update: (request: HttpRequest) -> (HttpResponse);

deploy_archive: (wasm: blob) -> (DeployArchiveResult);
/// Returns a batch of entries _sorted by sequence number_ to be archived.
/// This is an update call because the archive information _must_ be certified.
/// Only callable by this IIs archive canister.
// Returns a batch of entries _sorted by sequence number_ to be archived.
// This is an update call because the archive information _must_ be certified.
// Only callable by this IIs archive canister.
fetch_entries: () -> (vec BufferedArchiveEntry);
acknowledge_entries: (sequence_number: nat64) -> ();

// V2 API
// WARNING: The following methods are experimental and may change in the future.
//
// Note: the responses of v2 API calls are `opt` for compatibility reasons
// with future variant extensions.
// A client decoding a response as `null` indicates outdated type information
// and should be treated as an error.

// Creates a new captcha. The solution needs to be submitted using the
// `identity_register` call.
captcha_create: () -> (variant {Ok: Challenge; Err;});

// Registers a new identity with the given authn_method.
// A valid captcha solution to a previously generated captcha (using create_captcha) must be provided.
// The sender needs to match the supplied authn_method.
identity_register: (AuthnMethodData, CaptchaResult, opt principal) -> (variant {Ok: IdentityNumber; Err: IdentityRegisterError;});

// Returns information about the authentication methods of the identity with the given number.
// Only returns the minimal information required for authentication without exposing any metadata such as aliases.
identity_authn_info: (IdentityNumber) -> (variant {Ok: IdentityAuthnInfo; Err;}) query;

// Returns information about the identity with the given number.
// Requires authentication.
identity_info: (IdentityNumber) -> (opt IdentityInfoResponse);
identity_info: (IdentityNumber) -> (variant {Ok: IdentityInfo; Err: IdentityInfoError;});

// Replaces the authentication method independent metadata map.
// The existing metadata map will be overwritten.
// Requires authentication.
identity_metadata_replace: (IdentityNumber, MetadataMap) -> (opt IdentityMetadataReplaceResponse);
identity_metadata_replace: (IdentityNumber, MetadataMapV2) -> (variant {Ok; Err: IdentityMetadataReplaceError;});

// Adds a new authentication method to the identity.
// Requires authentication.
authn_method_add: (IdentityNumber, AuthnMethodData) -> (opt AuthnMethodAddResponse);
authn_method_add: (IdentityNumber, AuthnMethodData) -> (variant {Ok; Err: AuthnMethodAddError;});

// Atomically replaces the authentication method matching the supplied public key with the new authentication method
// provided.
// Requires authentication.
authn_method_replace: (IdentityNumber, PublicKey, AuthnMethodData) -> (variant {Ok; Err: AuthnMethodReplaceError;});

// Replaces the authentication method metadata map.
// The existing metadata map will be overwritten.
// Requires authentication.
authn_method_metadata_replace: (IdentityNumber, PublicKey, MetadataMapV2) -> (variant {Ok; Err: AuthnMethodMetadataReplaceError;});

// Replaces the authentication method security settings.
// The existing security settings will be overwritten.
// Requires authentication.
authn_method_security_settings_replace: (IdentityNumber, PublicKey, AuthnMethodSecuritySettings) -> (variant {Ok; Err: AuthnMethodSecuritySettingsReplaceError;});

// Removes the authentication method associated with the public key from the identity.
// Requires authentication.
authn_method_remove: (IdentityNumber, PublicKey) -> (opt AuthnMethodRemoveResponse);
authn_method_remove: (IdentityNumber, PublicKey) -> (variant {Ok; Err;});

// Enters the authentication method registration mode for the identity.
// In this mode, a new authentication method can be registered, which then needs to be
// confirmed before it can be used for authentication on this identity.
// The registration mode is automatically exited after the returned expiration timestamp.
// Requires authentication.
authn_method_registration_mode_enter : (IdentityNumber) -> (variant {Ok: record { expiration: Timestamp; }; Err;});

// Exits the authentication method registration mode for the identity.
// Requires authentication.
authn_method_registration_mode_exit : (IdentityNumber) -> (variant {Ok; Err;});

// Registers a new authentication method to the identity.
// This authentication method needs to be confirmed before it can be used for authentication on this identity.
authn_method_register: (IdentityNumber, AuthnMethodData) -> (variant {Ok: AuthnMethodConfirmationCode; Err: AuthnMethodRegisterError;});

// Confirms a previously registered authentication method.
// On successful confirmation, the authentication method is permanently added to the identity and can
// subsequently be used for authentication for that identity.
// Requires authentication.
authn_method_confirm: (IdentityNumber, confirmation_code: text) -> (variant {Ok; Err: AuthnMethodConfirmationError;});

// Attribute Sharing MVP API
// The methods below are used to generate ID-alias credentials during attribute sharing flow.
prepare_id_alias : (PrepareIdAliasRequest) -> (opt PrepareIdAliasResponse);
get_id_alias : (GetIdAliasRequest) -> (opt GetIdAliasResponse) query;
prepare_id_alias : (PrepareIdAliasRequest) -> (variant {Ok: PreparedIdAlias; Err: PrepareIdAliasError;});
get_id_alias : (GetIdAliasRequest) -> (variant {Ok: IdAliasCredentials; Err: GetIdAliasError;}) query;
}
4 changes: 3 additions & 1 deletion motoko/auth_client_demo/deps/pulled.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
"canisters": {
"rdmx6-jaaaa-aaaaa-aaadq-cai": {
"name": "internet-identity",
"wasm_hash": "17620cf418fae5bf743db00256451c164794c4bd0ddd23668571c21bdc525884",
"wasm_hash": "01797eac7db02126e7cb507e2f3134e2d7b5154289808fdc2c8c03d1fc2dc60e",
"wasm_hash_download": "01797eac7db02126e7cb507e2f3134e2d7b5154289808fdc2c8c03d1fc2dc60e",
"init_guide": "Use '(null)' for sensible defaults. See the candid interface for more details.",
"init_arg": null,
"candid_args": "(opt InternetIdentityInit)",
"gzip": true
}
Expand Down
18 changes: 1 addition & 17 deletions motoko/auth_client_demo/dfx.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,24 +26,8 @@
"src/auth_client_demo_assets/vanilla/dist"
],
"type": "assets"
},
"svelte": {
"dependencies": [
"whoami",
"internet-identity"
],
"source": [
"src/auth_client_demo_assets/svelte/build"
],
"type": "assets"
}
},
"defaults": {
"build": {
"args": "",
"packtool": ""
}
},
"output_env_file": ".env",
"version": 2
"version": 3
}
Loading

0 comments on commit ed793f9

Please sign in to comment.