diff --git a/proposals/proposal-267.sh b/proposals/proposal-267.sh new file mode 100755 index 0000000..7c2b4db --- /dev/null +++ b/proposals/proposal-267.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Load the environment variables +source "$(pwd)"/proposals/env.sh + +# build and get batch_id, evidence: +# dfx deploy ic_message_frontend --ic --by-proposal + +export BLOB="$(didc encode --format blob '(record {batch_id=40:nat; evidence=blob "\fe\dc\ef\ba\6f\8b\d5\f2\7a\61\67\09\b4\21\a6\08\dc\11\c4\11\06\cd\c6\45\71\59\e6\2f\1d\2c\e9\f1"})')" + +quill sns make-proposal --canister-ids-file ./sns_canister_ids.json --pem-file $PROPOSAL_PEM_FILE $PROPOSAL_NEURON_ID --proposal "( + record { + title = \"Execute commit_proposed_batch() to release ic_message_frontend v2.8.5\"; + url = \"https://dMsg.net/\"; + summary = \"This proposal executes commit_proposed_batch() on 2fvu6-tqaaa-aaaap-akksa-cai to release ic_message_frontend v2.8.5.\n\n1. feat: add token price info.\"; + action = opt variant { + ExecuteGenericNervousSystemFunction = record { + function_id = 1100 : nat64; + payload = ${BLOB}; + } + }; + } +)" > proposal-message.json + +# quill send proposal-message.json diff --git a/proposals/proposal-268.sh b/proposals/proposal-268.sh new file mode 100755 index 0000000..0625fa9 --- /dev/null +++ b/proposals/proposal-268.sh @@ -0,0 +1,25 @@ +#!/usr/bin/env bash + +# Load the environment variables +source "$(pwd)"/proposals/env.sh + +# build and get batch_id, evidence: +# dfx deploy ic_message_frontend --ic --by-proposal + +export BLOB="$(didc encode --format blob '(record {batch_id=41:nat; evidence=blob "\ad\98\2d\a3\bf\62\82\20\54\cb\3c\88\06\64\24\ab\e2\b5\01\a1\60\7b\49\ef\68\65\31\26\79\41\c0\d3"})')" + +quill sns make-proposal --canister-ids-file ./sns_canister_ids.json --pem-file $PROPOSAL_PEM_FILE $PROPOSAL_NEURON_ID --proposal "( + record { + title = \"Execute commit_proposed_batch() to release ic_message_frontend v2.8.6\"; + url = \"https://dMsg.net/\"; + summary = \"This proposal executes commit_proposed_batch() on 2fvu6-tqaaa-aaaap-akksa-cai to release ic_message_frontend v2.8.6.\n\n1. chore: improve token price reactivity in wallet.\"; + action = opt variant { + ExecuteGenericNervousSystemFunction = record { + function_id = 1100 : nat64; + payload = ${BLOB}; + } + }; + } +)" > proposal-message.json + +# quill send proposal-message.json diff --git a/src/ic_message_frontend/package.json b/src/ic_message_frontend/package.json index b07414c..f2fffba 100644 --- a/src/ic_message_frontend/package.json +++ b/src/ic_message_frontend/package.json @@ -83,5 +83,5 @@ "test": "vitest run" }, "type": "module", - "version": "2.8.5" + "version": "2.8.6" } \ No newline at end of file diff --git a/src/ic_message_frontend/src/app.html b/src/ic_message_frontend/src/app.html index 362a26f..8188a21 100644 --- a/src/ic_message_frontend/src/app.html +++ b/src/ic_message_frontend/src/app.html @@ -9,7 +9,7 @@ diff --git a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did index ccf075f..f944990 100644 --- a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did +++ b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did @@ -144,7 +144,9 @@ type AssetCanisterArgs = variant { Upgrade: UpgradeArgs; }; -type InitArgs = record {}; +type InitArgs = record { + set_permissions: opt SetPermissions; +}; type UpgradeArgs = record { set_permissions: opt SetPermissions; diff --git a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.d.ts b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.d.ts index 5412f47..be435d7 100644 --- a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.d.ts +++ b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.d.ts @@ -65,7 +65,7 @@ export interface HttpResponse { 'streaming_strategy' : [] | [StreamingStrategy], 'status_code' : number, } -export type InitArgs = {}; +export interface InitArgs { 'set_permissions' : [] | [SetPermissions] } export type Key = string; export interface ListPermitted { 'permission' : Permission } export type Permission = { 'Prepare' : null } | diff --git a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.js b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.js index 00c0ddd..432b90e 100644 --- a/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.js +++ b/src/ic_message_frontend/src/declarations/ic_message_frontend/ic_message_frontend.did.js @@ -7,7 +7,7 @@ export const idlFactory = ({ IDL }) => { const UpgradeArgs = IDL.Record({ 'set_permissions' : IDL.Opt(SetPermissions), }); - const InitArgs = IDL.Record({}); + const InitArgs = IDL.Record({ 'set_permissions' : IDL.Opt(SetPermissions) }); const AssetCanisterArgs = IDL.Variant({ 'Upgrade' : UpgradeArgs, 'Init' : InitArgs, @@ -287,7 +287,7 @@ export const init = ({ IDL }) => { const UpgradeArgs = IDL.Record({ 'set_permissions' : IDL.Opt(SetPermissions), }); - const InitArgs = IDL.Record({}); + const InitArgs = IDL.Record({ 'set_permissions' : IDL.Opt(SetPermissions) }); const AssetCanisterArgs = IDL.Variant({ 'Upgrade' : UpgradeArgs, 'Init' : InitArgs, diff --git a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did index 50deea0..cb57b5e 100644 --- a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did +++ b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did @@ -3,6 +3,7 @@ type BucketInfo = record { total_chunks : nat64; trusted_eddsa_pub_keys : vec blob; managers : vec principal; + governance_canister : opt principal; name : text; max_custom_data_size : nat16; auditors : vec principal; @@ -79,6 +80,7 @@ type FolderInfo = record { }; type FolderName = record { id : nat32; name : text }; type InitArgs = record { + governance_canister : opt principal; name : text; max_custom_data_size : nat16; max_children : nat16; @@ -146,6 +148,7 @@ type UpdateFolderInput = record { name : opt text; }; type UpgradeArgs = record { + governance_canister : opt principal; max_custom_data_size : opt nat16; max_children : opt nat16; enable_hash_index : opt bool; diff --git a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.d.ts b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.d.ts index c9724ae..950f0a0 100644 --- a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.d.ts +++ b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.d.ts @@ -7,6 +7,7 @@ export interface BucketInfo { 'total_chunks' : bigint, 'trusted_eddsa_pub_keys' : Array, 'managers' : Array, + 'governance_canister' : [] | [Principal], 'name' : string, 'max_custom_data_size' : number, 'auditors' : Array, @@ -86,6 +87,7 @@ export interface FolderInfo { } export interface FolderName { 'id' : number, 'name' : string } export interface InitArgs { + 'governance_canister' : [] | [Principal], 'name' : string, 'max_custom_data_size' : number, 'max_children' : number, @@ -175,6 +177,7 @@ export interface UpdateFolderInput { 'name' : [] | [string], } export interface UpgradeArgs { + 'governance_canister' : [] | [Principal], 'max_custom_data_size' : [] | [number], 'max_children' : [] | [number], 'enable_hash_index' : [] | [boolean], diff --git a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.js b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.js index 34f2ad3..d873e60 100644 --- a/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.js +++ b/src/ic_message_frontend/src/declarations/ic_oss_bucket_02/ic_oss_bucket_02.did.js @@ -1,5 +1,6 @@ export const idlFactory = ({ IDL }) => { const UpgradeArgs = IDL.Record({ + 'governance_canister' : IDL.Opt(IDL.Principal), 'max_custom_data_size' : IDL.Opt(IDL.Nat16), 'max_children' : IDL.Opt(IDL.Nat16), 'enable_hash_index' : IDL.Opt(IDL.Bool), @@ -7,6 +8,7 @@ export const idlFactory = ({ IDL }) => { 'max_folder_depth' : IDL.Opt(IDL.Nat8), }); const InitArgs = IDL.Record({ + 'governance_canister' : IDL.Opt(IDL.Principal), 'name' : IDL.Text, 'max_custom_data_size' : IDL.Nat16, 'max_children' : IDL.Nat16, @@ -66,6 +68,7 @@ export const idlFactory = ({ IDL }) => { 'total_chunks' : IDL.Nat64, 'trusted_eddsa_pub_keys' : IDL.Vec(IDL.Vec(IDL.Nat8)), 'managers' : IDL.Vec(IDL.Principal), + 'governance_canister' : IDL.Opt(IDL.Principal), 'name' : IDL.Text, 'max_custom_data_size' : IDL.Nat16, 'auditors' : IDL.Vec(IDL.Principal), @@ -365,6 +368,7 @@ export const idlFactory = ({ IDL }) => { }; export const init = ({ IDL }) => { const UpgradeArgs = IDL.Record({ + 'governance_canister' : IDL.Opt(IDL.Principal), 'max_custom_data_size' : IDL.Opt(IDL.Nat16), 'max_children' : IDL.Opt(IDL.Nat16), 'enable_hash_index' : IDL.Opt(IDL.Bool), @@ -372,6 +376,7 @@ export const init = ({ IDL }) => { 'max_folder_depth' : IDL.Opt(IDL.Nat8), }); const InitArgs = IDL.Record({ + 'governance_canister' : IDL.Opt(IDL.Principal), 'name' : IDL.Text, 'max_custom_data_size' : IDL.Nat16, 'max_children' : IDL.Nat16, diff --git a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did index cedd7f5..ac3a7bf 100644 --- a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did +++ b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did @@ -144,7 +144,6 @@ type UpgradeArgs = record { change_fee_collector : opt ChangeFeeCollector; max_memo_length : opt nat16; feature_flags : opt FeatureFlags; - maximum_number_of_accounts: opt nat64; accounts_overflow_trim_quantity: opt nat64; change_archive_options : opt ChangeArchiveOptions; }; @@ -427,6 +426,7 @@ type ICRC3DataCertificate = record { type icrc21_consent_message_metadata = record { language: text; + utc_offset_minutes: opt int16; }; type icrc21_consent_message_spec = record { diff --git a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.d.ts b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.d.ts index a7fd61b..81e48c1 100644 --- a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.d.ts +++ b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.d.ts @@ -244,7 +244,6 @@ export interface UpgradeArgs { 'token_symbol' : [] | [string], 'transfer_fee' : [] | [bigint], 'metadata' : [] | [Array<[string, MetadataValue]>], - 'maximum_number_of_accounts' : [] | [bigint], 'accounts_overflow_trim_quantity' : [] | [bigint], 'change_fee_collector' : [] | [ChangeFeeCollector], 'max_memo_length' : [] | [number], @@ -266,7 +265,10 @@ export type icrc21_consent_message = { 'LineDisplayMessage' : { 'pages' : Array<{ 'lines' : Array }> } } | { 'GenericDisplayMessage' : string }; -export interface icrc21_consent_message_metadata { 'language' : string } +export interface icrc21_consent_message_metadata { + 'utc_offset_minutes' : [] | [number], + 'language' : string, +} export interface icrc21_consent_message_request { 'arg' : Uint8Array | number[], 'method' : string, diff --git a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.js b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.js index e78bf33..a0a58b8 100644 --- a/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.js +++ b/src/ic_message_frontend/src/declarations/icrc1_ledger_canister/icrc1_ledger_canister.did.js @@ -33,7 +33,6 @@ export const idlFactory = ({ IDL }) => { 'token_symbol' : IDL.Opt(IDL.Text), 'transfer_fee' : IDL.Opt(IDL.Nat), 'metadata' : IDL.Opt(IDL.Vec(IDL.Tuple(IDL.Text, MetadataValue))), - 'maximum_number_of_accounts' : IDL.Opt(IDL.Nat64), 'accounts_overflow_trim_quantity' : IDL.Opt(IDL.Nat64), 'change_fee_collector' : IDL.Opt(ChangeFeeCollector), 'max_memo_length' : IDL.Opt(IDL.Nat16), @@ -207,7 +206,10 @@ export const idlFactory = ({ IDL }) => { 'Ok' : BlockIndex, 'Err' : TransferError, }); - const icrc21_consent_message_metadata = IDL.Record({ 'language' : IDL.Text }); + const icrc21_consent_message_metadata = IDL.Record({ + 'utc_offset_minutes' : IDL.Opt(IDL.Int16), + 'language' : IDL.Text, + }); const icrc21_consent_message_spec = IDL.Record({ 'metadata' : icrc21_consent_message_metadata, 'device_spec' : IDL.Opt( @@ -448,7 +450,6 @@ export const init = ({ IDL }) => { 'token_symbol' : IDL.Opt(IDL.Text), 'transfer_fee' : IDL.Opt(IDL.Nat), 'metadata' : IDL.Opt(IDL.Vec(IDL.Tuple(IDL.Text, MetadataValue))), - 'maximum_number_of_accounts' : IDL.Opt(IDL.Nat64), 'accounts_overflow_trim_quantity' : IDL.Opt(IDL.Nat64), 'change_fee_collector' : IDL.Opt(ChangeFeeCollector), 'max_memo_length' : IDL.Opt(IDL.Nat16), diff --git a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did index 0164427..bdaf682 100644 --- a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did +++ b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did @@ -209,6 +209,33 @@ type RateLimitConfig = record { max_tokens: nat64; }; +// Captcha configuration +// Default: +// - max_unsolved_captchas: 500 +// - captcha_trigger: Static, CaptchaEnabled +type CaptchaConfig = record { + // Maximum number of unsolved captchas. + max_unsolved_captchas : nat64; + // Configuration for when captcha protection should kick in. + captcha_trigger: variant { + // Based on the rate of registrations compared to some reference time frame and allowing some leeway. + Dynamic: record { + // Percentage of increased registration rate observed in the current rate sampling interval (compared to + // reference rate) at which II will enable captcha for new registrations. + threshold_pct: nat16; + // Length of the interval in seconds used to sample the current rate of registrations. + current_rate_sampling_interval_s: nat64; + // Length of the interval in seconds used to sample the reference rate of registrations. + reference_rate_sampling_interval_s: nat64; + }; + // Statically enable / disable captcha + Static: variant { + CaptchaEnabled; + CaptchaDisabled; + } + }; +}; + // Init arguments of II which can be supplied on install and upgrade. // Setting a value to null keeps the previous value. type InternetIdentityInit = record { @@ -228,9 +255,10 @@ type InternetIdentityInit = record { canister_creation_cycles_cost : opt nat64; // Rate limit for the `register` call. register_rate_limit : opt RateLimitConfig; - // Maximum number of inflight captchas. - // Default: 500 - max_inflight_captchas: opt nat64; + // Configuration of the captcha in the registration flow. + captcha_config: opt CaptchaConfig; + // Configuration for Related Origins Requests + related_origins: opt vec text; }; type ChallengeKey = text; @@ -403,23 +431,12 @@ type IdentityInfo = record { }; type IdentityInfoError = variant { - /// The principal is not authorized to call this method with the given arguments. + // The principal is not authorized to call this method with the given arguments. Unauthorized: principal; - /// Internal canister error. See the error message for details. + // Internal canister error. See the error message for details. InternalCanisterError: text; }; - - -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 AuthnMethodAddError = variant { InvalidMetadata: text; }; @@ -432,51 +449,51 @@ type AuthnMethodReplaceError = variant { type AuthnMethodMetadataReplaceError = variant { InvalidMetadata: text; - /// No authentication method found with the given public key. + // No authentication method found with the given public key. AuthnMethodNotFound; }; type AuthnMethodSecuritySettingsReplaceError = variant { - /// No authentication method found with the given public key. + // 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. + // 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. + // 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. + // Internal canister error. See the error message for details. InternalCanisterError: text; }; type PrepareIdAliasRequest = record { - /// Origin of the issuer in the attribute sharing flow. + // Origin of the issuer in the attribute sharing flow. issuer : FrontendHostname; - /// Origin of the relying party in the attribute sharing flow. + // Origin of the relying party in the attribute sharing flow. relying_party : FrontendHostname; - /// Identity for which the IdAlias should be generated. + // Identity for which the IdAlias should be generated. identity_number : IdentityNumber; }; type PrepareIdAliasError = variant { - /// The principal is not authorized to call this method with the given arguments. + // The principal is not authorized to call this method with the given arguments. Unauthorized: principal; - /// Internal canister error. See the error message for details. + // Internal canister error. See the error message for details. InternalCanisterError: text; }; -/// The prepared id alias contains two (still unsigned) credentials in JWT format, -/// certifying the id alias for the issuer resp. the relying party. +// The prepared id alias contains two (still unsigned) credentials in JWT format, +// certifying the id alias for the issuer resp. the relying party. type PreparedIdAlias = record { rp_id_alias_jwt : text; issuer_id_alias_jwt : text; canister_sig_pk_der : PublicKey; }; -/// The request to retrieve the actual signed id alias credentials. -/// The field values should be equal to the values of corresponding -/// fields from the preceding `PrepareIdAliasRequest` and `PrepareIdAliasResponse`. +// The request to retrieve the actual signed id alias credentials. +// The field values should be equal to the values of corresponding +// fields from the preceding `PrepareIdAliasRequest` and `PrepareIdAliasResponse`. type GetIdAliasRequest = record { rp_id_alias_jwt : text; issuer : FrontendHostname; @@ -486,15 +503,15 @@ type GetIdAliasRequest = record { }; type GetIdAliasError = variant { - /// The principal is not authorized to call this method with the given arguments. + // 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). + // The credential(s) are not available: may be expired or not prepared yet (call prepare_id_alias to prepare). NoSuchCredentials : text; - /// Internal canister error. See the error message for details. + // Internal canister error. See the error message for details. InternalCanisterError: text; }; -/// The signed id alias credentials for each involved party. +// The signed id alias credentials for each involved party. type IdAliasCredentials = record { rp_id_alias_credential : SignedIdAlias; issuer_id_alias_credential : SignedIdAlias; @@ -506,8 +523,76 @@ type SignedIdAlias = record { id_dapp : principal; }; +type IdRegNextStepResult = record { + // The next step in the registration flow + next_step: RegistrationFlowNextStep; +}; + +type IdRegStartError = variant { + // The method was called anonymously, which is not supported. + InvalidCaller; + // Too many registrations. Please try again later. + RateLimitExceeded; + // A registration flow is already in progress. + AlreadyInProgress; +}; + +// The next step in the registration flow: +// - CheckCaptcha: supply the solution to the captcha using `check_captcha` +// - Finish: finish the registration using `identity_registration_finish` +type RegistrationFlowNextStep = variant { + // Supply the captcha solution using check_captcha + CheckCaptcha: record { + captcha_png_base64: text; + }; + // Finish the registration using identity_registration_finish + Finish; +}; + +type CheckCaptchaArg = record { + solution : text; +}; + +type CheckCaptchaError = variant { + // The supplied solution was wrong. Try again with the new captcha. + WrongSolution: record { + new_captcha_png_base64: text; + }; + // This call is unexpected, see next_step. + UnexpectedCall: record { + next_step: RegistrationFlowNextStep; + }; + // No registration flow ongoing for the caller. + NoRegistrationFlow; +}; + +type IdRegFinishArg = record { + authn_method: AuthnMethodData; +}; + +type IdRegFinishResult = record { + identity_number: nat64; +}; + +type IdRegFinishError = variant { + // The configured maximum number of identities has been reached. + IdentityLimitReached; + // This call is unexpected, see next_step. + UnexpectedCall: record { + next_step: RegistrationFlowNextStep; + }; + // No registration flow ongoing for the caller. + NoRegistrationFlow; + // The supplied authn_method is not valid. + InvalidAuthnMethod: text; + // Error while persisting the new identity. + StorageError: text; +}; + service : (opt InternetIdentityInit) -> { - init_salt: () -> (); + // Legacy identity management API + // ============================== + create_challenge : () -> (Challenge); register : (DeviceData, ChallengeResult, opt principal) -> (RegisterResponse); add : (UserNumber, DeviceData) -> (); @@ -522,37 +607,25 @@ service : (opt InternetIdentityInit) -> { get_anchor_credentials : (UserNumber) -> (AnchorCredentials) query; get_anchor_info : (UserNumber) -> (IdentityAnchorInfo); get_principal : (UserNumber, FrontendHostname) -> (principal) query; - stats : () -> (InternetIdentityStats) query; enter_device_registration_mode : (UserNumber) -> (Timestamp); exit_device_registration_mode : (UserNumber) -> (); add_tentative_device : (UserNumber, DeviceData) -> (AddTentativeDeviceResponse); verify_tentative_device : (UserNumber, verification_code: text) -> (VerifyTentativeDeviceResponse); - prepare_delegation : (UserNumber, FrontendHostname, SessionKey, maxTimeToLive : opt nat64) -> (UserKey, Timestamp); - get_delegation: (UserNumber, FrontendHostname, SessionKey, Timestamp) -> (GetDelegationResponse) query; - - http_request: (request: HttpRequest) -> (HttpResponse) query; - 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. - fetch_entries: () -> (vec BufferedArchiveEntry); - acknowledge_entries: (sequence_number: nat64) -> (); + // V2 Identity Management API + // ========================== + // WARNING: The following methods are experimental and may ch 0ange in the future. - // V2 API - // WARNING: The following methods are experimental and may change in the future. + // Starts the identity registration flow to create a new identity. + identity_registration_start: () -> (variant {Ok: IdRegNextStepResult; Err: IdRegStartError;}); - // Creates a new captcha. The solution needs to be submitted using the - // `identity_register` call. - captcha_create: () -> (variant {Ok: Challenge; Err;}); + // Check the captcha challenge + // If successful, the registration can be finished with `identity_registration_finish`. + check_captcha: (CheckCaptchaArg) -> (variant {Ok: IdRegNextStepResult; Err: CheckCaptchaError;}); - // 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;}); + // Starts the identity registration flow to create a new identity. + identity_registration_finish: (IdRegFinishArg) -> (variant {Ok: IdRegFinishResult; Err: IdRegFinishError;}); // 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. @@ -611,8 +684,32 @@ service : (opt InternetIdentityInit) -> { // Requires authentication. authn_method_confirm: (IdentityNumber, confirmation_code: text) -> (variant {Ok; Err: AuthnMethodConfirmationError;}); + // Authentication protocol + // ======================= + prepare_delegation : (UserNumber, FrontendHostname, SessionKey, maxTimeToLive : opt nat64) -> (UserKey, Timestamp); + get_delegation: (UserNumber, FrontendHostname, SessionKey, Timestamp) -> (GetDelegationResponse) query; + // Attribute Sharing MVP API + // ========================= // The methods below are used to generate ID-alias credentials during attribute sharing flow. prepare_id_alias : (PrepareIdAliasRequest) -> (variant {Ok: PreparedIdAlias; Err: PrepareIdAliasError;}); get_id_alias : (GetIdAliasRequest) -> (variant {Ok: IdAliasCredentials; Err: GetIdAliasError;}) query; + + // HTTP Gateway protocol + // ===================== + http_request: (request: HttpRequest) -> (HttpResponse) query; + http_request_update: (request: HttpRequest) -> (HttpResponse); + + // Internal Methods + // ================ + init_salt: () -> (); + stats : () -> (InternetIdentityStats) query; + config : () -> (InternetIdentityInit) query; + + 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. + fetch_entries: () -> (vec BufferedArchiveEntry); + acknowledge_entries: (sequence_number: nat64) -> (); } diff --git a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.d.ts b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.d.ts index 5ea5582..89f7567 100644 --- a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.d.ts +++ b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.d.ts @@ -71,6 +71,17 @@ export interface BufferedArchiveEntry { 'anchor_number' : UserNumber, 'timestamp' : Timestamp, } +export interface CaptchaConfig { + 'max_unsolved_captchas' : bigint, + 'captcha_trigger' : { + 'Dynamic' : { + 'reference_rate_sampling_interval_s' : bigint, + 'threshold_pct' : number, + 'current_rate_sampling_interval_s' : bigint, + } + } | + { 'Static' : { 'CaptchaDisabled' : null } | { 'CaptchaEnabled' : null } }, +} export type CaptchaResult = ChallengeResult; export interface Challenge { 'png_base64' : string, @@ -78,6 +89,10 @@ export interface Challenge { } export type ChallengeKey = string; export interface ChallengeResult { 'key' : ChallengeKey, 'chars' : string } +export interface CheckCaptchaArg { 'solution' : string } +export type CheckCaptchaError = { 'NoRegistrationFlow' : null } | + { 'UnexpectedCall' : { 'next_step' : RegistrationFlowNextStep } } | + { 'WrongSolution' : { 'new_captcha_png_base64' : string } }; export type CredentialId = Uint8Array | number[]; export interface Delegation { 'pubkey' : PublicKey, @@ -147,6 +162,17 @@ export interface IdAliasCredentials { 'rp_id_alias_credential' : SignedIdAlias, 'issuer_id_alias_credential' : SignedIdAlias, } +export interface IdRegFinishArg { 'authn_method' : AuthnMethodData } +export type IdRegFinishError = { 'NoRegistrationFlow' : null } | + { 'UnexpectedCall' : { 'next_step' : RegistrationFlowNextStep } } | + { 'InvalidAuthnMethod' : string } | + { 'IdentityLimitReached' : null } | + { 'StorageError' : string }; +export interface IdRegFinishResult { 'identity_number' : bigint } +export interface IdRegNextStepResult { 'next_step' : RegistrationFlowNextStep } +export type IdRegStartError = { 'InvalidCaller' : null } | + { 'AlreadyInProgress' : null } | + { 'RateLimitExceeded' : null }; export interface IdentityAnchorInfo { 'devices' : Array, 'device_registration' : [] | [DeviceRegistrationInfo], @@ -173,14 +199,12 @@ export type IdentityMetadataReplaceError = { } }; export type IdentityNumber = bigint; -export type IdentityRegisterError = { 'BadCaptcha' : null } | - { 'CanisterFull' : null } | - { 'InvalidMetadata' : string }; export interface InternetIdentityInit { 'assigned_user_number_range' : [] | [[bigint, bigint]], - 'max_inflight_captchas' : [] | [bigint], 'archive_config' : [] | [ArchiveConfig], 'canister_creation_cycles_cost' : [] | [bigint], + 'related_origins' : [] | [Array], + 'captcha_config' : [] | [CaptchaConfig], 'register_rate_limit' : [] | [RateLimitConfig], } export interface InternetIdentityStats { @@ -235,6 +259,10 @@ export interface RateLimitConfig { export type RegisterResponse = { 'bad_challenge' : null } | { 'canister_full' : null } | { 'registered' : { 'user_number' : UserNumber } }; +export type RegistrationFlowNextStep = { + 'CheckCaptcha' : { 'captcha_png_base64' : string } + } | + { 'Finish' : null }; export type SessionKey = PublicKey; export interface SignedDelegation { 'signature' : Uint8Array | number[], @@ -322,7 +350,12 @@ export interface _SERVICE { { 'Ok' : null } | { 'Err' : AuthnMethodSecuritySettingsReplaceError } >, - 'captcha_create' : ActorMethod<[], { 'Ok' : Challenge } | { 'Err' : null }>, + 'check_captcha' : ActorMethod< + [CheckCaptchaArg], + { 'Ok' : IdRegNextStepResult } | + { 'Err' : CheckCaptchaError } + >, + 'config' : ActorMethod<[], InternetIdentityInit>, 'create_challenge' : ActorMethod<[], Challenge>, 'deploy_archive' : ActorMethod<[Uint8Array | number[]], DeployArchiveResult>, 'enter_device_registration_mode' : ActorMethod<[UserNumber], Timestamp>, @@ -357,10 +390,15 @@ export interface _SERVICE { { 'Ok' : null } | { 'Err' : IdentityMetadataReplaceError } >, - 'identity_register' : ActorMethod< - [AuthnMethodData, CaptchaResult, [] | [Principal]], - { 'Ok' : IdentityNumber } | - { 'Err' : IdentityRegisterError } + 'identity_registration_finish' : ActorMethod< + [IdRegFinishArg], + { 'Ok' : IdRegFinishResult } | + { 'Err' : IdRegFinishError } + >, + 'identity_registration_start' : ActorMethod< + [], + { 'Ok' : IdRegNextStepResult } | + { 'Err' : IdRegStartError } >, 'init_salt' : ActorMethod<[], undefined>, 'lookup' : ActorMethod<[UserNumber], Array>, diff --git a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.js b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.js index c0eb4f8..fb954bd 100644 --- a/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.js +++ b/src/ic_message_frontend/src/declarations/internet_identity/internet_identity.did.js @@ -7,15 +7,30 @@ export const idlFactory = ({ IDL }) => { 'module_hash' : IDL.Vec(IDL.Nat8), 'entries_fetch_limit' : IDL.Nat16, }); + const CaptchaConfig = IDL.Record({ + 'max_unsolved_captchas' : IDL.Nat64, + 'captcha_trigger' : IDL.Variant({ + 'Dynamic' : IDL.Record({ + 'reference_rate_sampling_interval_s' : IDL.Nat64, + 'threshold_pct' : IDL.Nat16, + 'current_rate_sampling_interval_s' : IDL.Nat64, + }), + 'Static' : IDL.Variant({ + 'CaptchaDisabled' : IDL.Null, + 'CaptchaEnabled' : IDL.Null, + }), + }), + }); const RateLimitConfig = IDL.Record({ 'max_tokens' : IDL.Nat64, 'time_per_token_ns' : IDL.Nat64, }); const InternetIdentityInit = IDL.Record({ 'assigned_user_number_range' : IDL.Opt(IDL.Tuple(IDL.Nat64, IDL.Nat64)), - 'max_inflight_captchas' : IDL.Opt(IDL.Nat64), 'archive_config' : IDL.Opt(ArchiveConfig), 'canister_creation_cycles_cost' : IDL.Opt(IDL.Nat64), + 'related_origins' : IDL.Opt(IDL.Vec(IDL.Text)), + 'captcha_config' : IDL.Opt(CaptchaConfig), 'register_rate_limit' : IDL.Opt(RateLimitConfig), }); const UserNumber = IDL.Nat64; @@ -134,6 +149,19 @@ export const idlFactory = ({ IDL }) => { const AuthnMethodSecuritySettingsReplaceError = IDL.Variant({ 'AuthnMethodNotFound' : IDL.Null, }); + const CheckCaptchaArg = IDL.Record({ 'solution' : IDL.Text }); + const RegistrationFlowNextStep = IDL.Variant({ + 'CheckCaptcha' : IDL.Record({ 'captcha_png_base64' : IDL.Text }), + 'Finish' : IDL.Null, + }); + const IdRegNextStepResult = IDL.Record({ + 'next_step' : RegistrationFlowNextStep, + }); + const CheckCaptchaError = IDL.Variant({ + 'NoRegistrationFlow' : IDL.Null, + 'UnexpectedCall' : IDL.Record({ 'next_step' : RegistrationFlowNextStep }), + 'WrongSolution' : IDL.Record({ 'new_captcha_png_base64' : IDL.Text }), + }); const ChallengeKey = IDL.Text; const Challenge = IDL.Record({ 'png_base64' : IDL.Text, @@ -269,15 +297,19 @@ export const idlFactory = ({ IDL }) => { 'space_available' : IDL.Nat64, }), }); - const ChallengeResult = IDL.Record({ - 'key' : ChallengeKey, - 'chars' : IDL.Text, + const IdRegFinishArg = IDL.Record({ 'authn_method' : AuthnMethodData }); + const IdRegFinishResult = IDL.Record({ 'identity_number' : IDL.Nat64 }); + const IdRegFinishError = IDL.Variant({ + 'NoRegistrationFlow' : IDL.Null, + 'UnexpectedCall' : IDL.Record({ 'next_step' : RegistrationFlowNextStep }), + 'InvalidAuthnMethod' : IDL.Text, + 'IdentityLimitReached' : IDL.Null, + 'StorageError' : IDL.Text, }); - const CaptchaResult = ChallengeResult; - const IdentityRegisterError = IDL.Variant({ - 'BadCaptcha' : IDL.Null, - 'CanisterFull' : IDL.Null, - 'InvalidMetadata' : IDL.Text, + const IdRegStartError = IDL.Variant({ + 'InvalidCaller' : IDL.Null, + 'AlreadyInProgress' : IDL.Null, + 'RateLimitExceeded' : IDL.Null, }); const UserKey = PublicKey; const PrepareIdAliasRequest = IDL.Record({ @@ -294,6 +326,10 @@ export const idlFactory = ({ IDL }) => { 'InternalCanisterError' : IDL.Text, 'Unauthorized' : IDL.Principal, }); + const ChallengeResult = IDL.Record({ + 'key' : ChallengeKey, + 'chars' : IDL.Text, + }); const RegisterResponse = IDL.Variant({ 'bad_challenge' : IDL.Null, 'canister_full' : IDL.Null, @@ -397,11 +433,17 @@ export const idlFactory = ({ IDL }) => { ], [], ), - 'captcha_create' : IDL.Func( - [], - [IDL.Variant({ 'Ok' : Challenge, 'Err' : IDL.Null })], + 'check_captcha' : IDL.Func( + [CheckCaptchaArg], + [ + IDL.Variant({ + 'Ok' : IdRegNextStepResult, + 'Err' : CheckCaptchaError, + }), + ], [], ), + 'config' : IDL.Func([], [InternetIdentityInit], ['query']), 'create_challenge' : IDL.Func([], [Challenge], []), 'deploy_archive' : IDL.Func([IDL.Vec(IDL.Nat8)], [DeployArchiveResult], []), 'enter_device_registration_mode' : IDL.Func([UserNumber], [Timestamp], []), @@ -450,9 +492,14 @@ export const idlFactory = ({ IDL }) => { ], [], ), - 'identity_register' : IDL.Func( - [AuthnMethodData, CaptchaResult, IDL.Opt(IDL.Principal)], - [IDL.Variant({ 'Ok' : IdentityNumber, 'Err' : IdentityRegisterError })], + 'identity_registration_finish' : IDL.Func( + [IdRegFinishArg], + [IDL.Variant({ 'Ok' : IdRegFinishResult, 'Err' : IdRegFinishError })], + [], + ), + 'identity_registration_start' : IDL.Func( + [], + [IDL.Variant({ 'Ok' : IdRegNextStepResult, 'Err' : IdRegStartError })], [], ), 'init_salt' : IDL.Func([], [], []), @@ -490,15 +537,30 @@ export const init = ({ IDL }) => { 'module_hash' : IDL.Vec(IDL.Nat8), 'entries_fetch_limit' : IDL.Nat16, }); + const CaptchaConfig = IDL.Record({ + 'max_unsolved_captchas' : IDL.Nat64, + 'captcha_trigger' : IDL.Variant({ + 'Dynamic' : IDL.Record({ + 'reference_rate_sampling_interval_s' : IDL.Nat64, + 'threshold_pct' : IDL.Nat16, + 'current_rate_sampling_interval_s' : IDL.Nat64, + }), + 'Static' : IDL.Variant({ + 'CaptchaDisabled' : IDL.Null, + 'CaptchaEnabled' : IDL.Null, + }), + }), + }); const RateLimitConfig = IDL.Record({ 'max_tokens' : IDL.Nat64, 'time_per_token_ns' : IDL.Nat64, }); const InternetIdentityInit = IDL.Record({ 'assigned_user_number_range' : IDL.Opt(IDL.Tuple(IDL.Nat64, IDL.Nat64)), - 'max_inflight_captchas' : IDL.Opt(IDL.Nat64), 'archive_config' : IDL.Opt(ArchiveConfig), 'canister_creation_cycles_cost' : IDL.Opt(IDL.Nat64), + 'related_origins' : IDL.Opt(IDL.Vec(IDL.Text)), + 'captcha_config' : IDL.Opt(CaptchaConfig), 'register_rate_limit' : IDL.Opt(RateLimitConfig), }); return [IDL.Opt(InternetIdentityInit)]; diff --git a/src/ic_message_frontend/src/lib/components/core/MoreMenuPopup.svelte b/src/ic_message_frontend/src/lib/components/core/MoreMenuPopup.svelte index 9f8aa94..e7805b7 100644 --- a/src/ic_message_frontend/src/lib/components/core/MoreMenuPopup.svelte +++ b/src/ic_message_frontend/src/lib/components/core/MoreMenuPopup.svelte @@ -51,7 +51,7 @@ href="https://app.icpswap.com/swap?input=ryjl3-tyaaa-aaaaa-aaaba-cai&output=druyg-tyaaa-aaaaq-aactq-cai" > - Exchange $PANDA + Exchange PANDA diff --git a/src/ic_message_frontend/src/lib/components/core/WalletDetailModal.svelte b/src/ic_message_frontend/src/lib/components/core/WalletDetailModal.svelte index 63dc94d..99be6f3 100644 --- a/src/ic_message_frontend/src/lib/components/core/WalletDetailModal.svelte +++ b/src/ic_message_frontend/src/lib/components/core/WalletDetailModal.svelte @@ -1,6 +1,5 @@