Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .sources/VERSIONS
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,4 @@
# -------------------------------------------------------

motoko v1.16.1 01aee06
internetidentity release-2026-09-11 3cd91d62
internetidentity release-2026-09-25 64ba1637
2 changes: 1 addition & 1 deletion .sources/internetidentity
Submodule internetidentity updated 181 files
194 changes: 194 additions & 0 deletions public/references/internet-identity.did
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,11 @@ type InternetIdentityInit = record {
// `https` for every discovery host. Never enable in production — non-loopback
// hosts always require `https` regardless.
sso_allow_insecure_discovery : opt bool;
// Deploy flag relaxing the https requirement for sender-list outcalls to
// loopback hosts (localhost / 127.0.0.1) so e2e tests and local development can
// serve the list over plain http. null / opt false (the default) require https
// for every notifying origin, and a non-loopback origin always requires https.
notifications_allow_insecure_sender_list : opt bool;
// Configuration for Web Analytics
analytics_config : opt opt AnalyticsConfig;
// Configuration to show dapps explorer or not
Expand Down Expand Up @@ -334,6 +339,12 @@ type InternetIdentityInit = record {
// set/clear pattern as `dnssec_config`: null keeps the previously stored
// value, `opt null` clears it, `opt opt "https://..."` sets it.
mcp_official_url : opt opt text;
// Server-side kill switch for the notifications feature. null / `opt false`
// (the default) disables every notification endpoint; `opt true` enables
// them. Omitting it on upgrade keeps the stored value.
// Apps allowed to notify. Omitted on upgrade keeps the stored list, an empty list
// turns notifications off, and entries enable them for those origins only.
notifications_enabled_origins : opt vec text;
};

// DNSSEC trust-anchor list. Any feature that needs DNSSEC-verified DNS
Expand Down Expand Up @@ -540,6 +551,14 @@ type OpenIdDelegationError = variant {
JwtVerificationFailed;
NoSuchDelegation;
JwtExpired;
// The credential is registered on an anchor, but through a different SSO
// discovery domain than the one this login was verified through, so the
// domain-scoped anchor lookup cannot resolve it. `registered_sso_domain` is
// the domain the credential is registered through (`null` for a credential
// stored without a domain stamp). A sign-up with the same credential would be
// rejected with `OpenIdCredentialAlreadyRegistered`, since registration
// uniqueness spans all discovery domains.
SsoDomainMismatch : record { registered_sso_domain : opt text };
};

type OpenIdPrepareDelegationResponse = record {
Expand Down Expand Up @@ -1732,6 +1751,162 @@ type ListAvailableAttributesError = variant {
AuthorizationError : principal;
};

// Why a notification call was refused.
type NotificationGrantConsentError = variant {
Unauthorized : principal;
InternalCanisterError : text;
};

type NotificationRevokeConsentError = variant {
Unauthorized : principal;
InternalCanisterError : text;
};

type NotificationGrantConsentRequest = record {
anchor_number : UserNumber;
origin : text;
};

type NotificationRevokeConsentRequest = record {
anchor_number : UserNumber;
origin : text;
};

type NotificationConsentGrantedRequest = record {
anchor_number : UserNumber;
origin : text;
};

// What a browser uploads when it registers for Web Push, and how it replaces a pool
// that is running out: the same endpoint with a newer jwt_issued_at_ns. Signed with the
// browser key it signs in with, which is what says the subscription is this browser's.
type SetWebPushSubscriptionRequest = record {
anchor_number : UserNumber;
endpoint : text; // the relay URL the browser was issued
vapid_public_key : blob; // uncompressed SEC1 P-256, echoed to the relay as k=
jwt_signatures : vec blob; // one raw ECDSA signature per validity window
jwt_issued_at_ns : nat64;
};

type RemoveWebPushSubscriptionRequest = record {
anchor_number : UserNumber;
browser_id : nat32;
};

type SetWebPushSubscriptionError = variant {
// The caller signs with no key this identity is signed in from.
InvalidBrowserKey;
// The pool offered is not newer than the one this endpoint already holds.
StaleJwtPool;
InternalCanisterError : text;
};

type RemoveWebPushSubscriptionError = variant {
Unauthorized : principal;
InternalCanisterError : text;
};

type GetWebPushSubscriptionStatusRequest = record {
anchor_number : UserNumber;
};

// What a browser is registered with, so the frontend can tell a registration that is
// still live from one another identity's re-subscribe left behind, and knows when to
// sign the next pool.
type WebPushSubscriptionStatus = record {
endpoint : text; // compared against the one the browser holds
pool_len : nat32; // windows covered, not a count of unused signatures
issued_at_ns : nat64; // window i expires at issued_at_ns + (i + 1) * window
};

// ===== Notifications sent by an app =====

// Scoped to (origin, recipient), and shared across the canisters sending for
// one origin.
type NotificationId = nat64;

type Urgency = variant { VeryLow; Low; Normal; High };

type Notification = record {
id : NotificationId;
recipient : principal;
// Null means II's default retention, which is also the ceiling.
expires_at : opt Timestamp;
// Null means Normal.
urgency : opt Urgency;
};

// Applies in order: a later entry for a (recipient, id) replaces an earlier
// one, as a re-send replaces a notification that is still pending.
type SendNotificationArg = record {
origin : FrontendHostname;
notifications : vec Notification;
};

type NotAcceptedReason = variant {
NoSuchRecipient;
NoChannel;
Deferred : record { retry_after : Timestamp };
};

type NotAccepted = record {
id : NotificationId;
recipient : principal;
reason : NotAcceptedReason;
};

// Anything not_accepted does not name was accepted.
type SendNotificationResponse = record {
not_accepted : vec NotAccepted;
};

type SendNotificationError = variant {
// The origin lists no such sender: no file, an empty or unusable one, or
// one that does not name the caller.
NoSuchSender;
TooManyNotifications : record { limit : nat32 };
InternalCanisterError : text;
};

// ===== Notification pull delegation =====

type PrepareNotificationDelegationRequest = record {
anchor_number : UserNumber;
origin : FrontendHostname;
account_number : opt AccountNumber; // null = the unreserved default account
session_key : SessionKey;
};

type PrepareNotificationDelegationResponse = record {
user_key : UserKey;
expiration : Timestamp;
// Goes in the sender_info field of every call made with this delegation;
// tells the app which account it is being called for.
sender_info : blob;
};

type GetNotificationDelegationRequest = record {
anchor_number : UserNumber;
origin : FrontendHostname;
account_number : opt AccountNumber; // null = the unreserved default account
session_key : SessionKey;
expiration : Timestamp;
};

type GetNotificationDelegationResponse = record {
signed_delegation : SignedDelegation;
// Authenticates sender_info on those calls.
sender_info_signature : blob;
};

type NotificationDelegationError = variant {
// The caller is no browser of this identity, that browser is not registered
// for Web Push, or the identity has not allowed this app to notify it.
NoNotificationAccess;
NoSuchDelegation;
InternalCanisterError : text;
};

service : (opt InternetIdentityInit) -> {
// Legacy identity management API
// ==============================
Expand Down Expand Up @@ -2206,4 +2381,23 @@ service : (opt InternetIdentityInit) -> {

// Looks up identity number when called with a recovery phrase
lookup_caller_identity_by_recovery_phrase : () -> (opt IdentityNumber);

// ===== Notifications =====
notification_grant_consent : (NotificationGrantConsentRequest) -> (variant { Ok; Err : NotificationGrantConsentError });
notification_revoke_consent : (NotificationRevokeConsentRequest) -> (variant { Ok; Err : NotificationRevokeConsentError });
notification_consent_granted : (NotificationConsentGrantedRequest) -> (bool) query;

// Authorized by the browser key the caller signs with.
prepare_notification_delegation : (PrepareNotificationDelegationRequest) -> (variant { Ok : PrepareNotificationDelegationResponse; Err : NotificationDelegationError });
get_notification_delegation : (GetNotificationDelegationRequest) -> (variant { Ok : GetNotificationDelegationResponse; Err : NotificationDelegationError }) query;

// Called by the browser itself, signed with the browser key it signs in with.
set_webpush_subscription : (SetWebPushSubscriptionRequest) -> (variant { Ok; Err : SetWebPushSubscriptionError });
// Called by the identity, so one browser can silence another.
remove_webpush_subscription : (RemoveWebPushSubscriptionRequest) -> (variant { Ok; Err : RemoveWebPushSubscriptionError });
get_webpush_subscription_status : (GetWebPushSubscriptionStatusRequest) -> (opt WebPushSubscriptionStatus) query;

// Called by an app's backend canister for the origin it names. Not
// implemented yet: every call is refused.
app_send_notification : (SendNotificationArg) -> (variant { Ok : SendNotificationResponse; Err : SendNotificationError });
};
Loading