From 773bd90eda05882ff5180e162fd4d71aa4c9418f Mon Sep 17 00:00:00 2001 From: Chirag Aggarwal Date: Mon, 12 Oct 2026 17:56:58 +0100 Subject: [PATCH] feat: add passkeys for version 28.3.0 --- CHANGELOG.md | 8 + appwrite.gemspec | 2 +- docs/examples/account/create-passkey-token.md | 14 + docs/examples/account/create-passkey.md | 17 + docs/examples/account/delete-passkey.md | 16 + docs/examples/account/get-passkey.md | 16 + docs/examples/account/list-passkeys.md | 17 + docs/examples/account/update-passkey-token.md | 17 + .../account/update-passkey-verification.md | 17 + docs/examples/account/update-passkey.md | 17 + .../examples/project/update-passkey-policy.md | 16 + docs/examples/users/delete-passkey.md | 17 + docs/examples/users/get-passkey.md | 17 + docs/examples/users/list-passkeys.md | 18 ++ docs/examples/users/update-passkey.md | 18 ++ lib/appwrite.rb | 4 + lib/appwrite/client.rb | 2 +- lib/appwrite/models/passkey.rb | 47 +++ lib/appwrite/models/passkey_challenge.rb | 47 +++ lib/appwrite/models/passkey_list.rb | 32 ++ lib/appwrite/models/token_secret.rb | 52 +++ lib/appwrite/services/account.rb | 298 ++++++++++++++++++ lib/appwrite/services/project.rb | 38 +++ lib/appwrite/services/users.rb | 162 ++++++++++ 24 files changed, 907 insertions(+), 2 deletions(-) create mode 100644 docs/examples/account/create-passkey-token.md create mode 100644 docs/examples/account/create-passkey.md create mode 100644 docs/examples/account/delete-passkey.md create mode 100644 docs/examples/account/get-passkey.md create mode 100644 docs/examples/account/list-passkeys.md create mode 100644 docs/examples/account/update-passkey-token.md create mode 100644 docs/examples/account/update-passkey-verification.md create mode 100644 docs/examples/account/update-passkey.md create mode 100644 docs/examples/project/update-passkey-policy.md create mode 100644 docs/examples/users/delete-passkey.md create mode 100644 docs/examples/users/get-passkey.md create mode 100644 docs/examples/users/list-passkeys.md create mode 100644 docs/examples/users/update-passkey.md create mode 100644 lib/appwrite/models/passkey.rb create mode 100644 lib/appwrite/models/passkey_challenge.rb create mode 100644 lib/appwrite/models/passkey_list.rb create mode 100644 lib/appwrite/models/token_secret.rb diff --git a/CHANGELOG.md b/CHANGELOG.md index 5051946..71bf869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Change Log +## 28.3.0 + +* Added: `account` passkey methods `listPasskeys`, `createPasskey`, `getPasskey`, `updatePasskey`, `deletePasskey` and `updatePasskeyVerification` +* Added: `account.createPasskeyToken` and `account.updatePasskeyToken` for passkey sign-in +* Added: `users.listPasskeys`, `users.getPasskey`, `users.updatePasskey` and `users.deletePasskey` +* Added: `project.updatePasskeyPolicy` to configure passkey sign-in +* Added: `Passkey`, `PasskeyList`, `PasskeyChallenge` and `TokenSecret` models + ## 28.2.0 * Added: optional `interval` parameter on `functions.create` and `functions.update` to run a function every N minutes diff --git a/appwrite.gemspec b/appwrite.gemspec index 14229fc..6a7b78c 100644 --- a/appwrite.gemspec +++ b/appwrite.gemspec @@ -1,6 +1,6 @@ Gem::Specification.new do |spec| spec.name = 'appwrite' - spec.version = '28.2.0' + spec.version = '28.3.0' spec.license = 'BSD-3-Clause' spec.summary = 'Appwrite is an open-source self-hosted backend server that abstracts and simplifies complex and repetitive development tasks behind a very simple REST API' spec.author = 'Appwrite Team' diff --git a/docs/examples/account/create-passkey-token.md b/docs/examples/account/create-passkey-token.md new file mode 100644 index 0000000..c3f48ed --- /dev/null +++ b/docs/examples/account/create-passkey-token.md @@ -0,0 +1,14 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.create_passkey_token() +``` diff --git a/docs/examples/account/create-passkey.md b/docs/examples/account/create-passkey.md new file mode 100644 index 0000000..c699aa2 --- /dev/null +++ b/docs/examples/account/create-passkey.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.create_passkey( + passkey_id: '', # optional + name: '' # optional +) +``` diff --git a/docs/examples/account/delete-passkey.md b/docs/examples/account/delete-passkey.md new file mode 100644 index 0000000..740ba97 --- /dev/null +++ b/docs/examples/account/delete-passkey.md @@ -0,0 +1,16 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.delete_passkey( + passkey_id: '' +) +``` diff --git a/docs/examples/account/get-passkey.md b/docs/examples/account/get-passkey.md new file mode 100644 index 0000000..705e41a --- /dev/null +++ b/docs/examples/account/get-passkey.md @@ -0,0 +1,16 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.get_passkey( + passkey_id: '' +) +``` diff --git a/docs/examples/account/list-passkeys.md b/docs/examples/account/list-passkeys.md new file mode 100644 index 0000000..8c58601 --- /dev/null +++ b/docs/examples/account/list-passkeys.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.list_passkeys( + queries: [], # optional + total: false # optional +) +``` diff --git a/docs/examples/account/update-passkey-token.md b/docs/examples/account/update-passkey-token.md new file mode 100644 index 0000000..406e91e --- /dev/null +++ b/docs/examples/account/update-passkey-token.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.update_passkey_token( + challenge_id: '', + credential: {} +) +``` diff --git a/docs/examples/account/update-passkey-verification.md b/docs/examples/account/update-passkey-verification.md new file mode 100644 index 0000000..fb2671d --- /dev/null +++ b/docs/examples/account/update-passkey-verification.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.update_passkey_verification( + passkey_id: '', + credential: {} +) +``` diff --git a/docs/examples/account/update-passkey.md b/docs/examples/account/update-passkey.md new file mode 100644 index 0000000..07f3ff3 --- /dev/null +++ b/docs/examples/account/update-passkey.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_session('') # The user session to authenticate with + +account = Account.new(client) + +result = account.update_passkey( + passkey_id: '', + name: '' +) +``` diff --git a/docs/examples/project/update-passkey-policy.md b/docs/examples/project/update-passkey-policy.md new file mode 100644 index 0000000..fd92c76 --- /dev/null +++ b/docs/examples/project/update-passkey-policy.md @@ -0,0 +1,16 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +project = Project.new(client) + +result = project.update_passkey_policy( + rp_id: '' +) +``` diff --git a/docs/examples/users/delete-passkey.md b/docs/examples/users/delete-passkey.md new file mode 100644 index 0000000..b07052f --- /dev/null +++ b/docs/examples/users/delete-passkey.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +users = Users.new(client) + +result = users.delete_passkey( + user_id: '', + passkey_id: '' +) +``` diff --git a/docs/examples/users/get-passkey.md b/docs/examples/users/get-passkey.md new file mode 100644 index 0000000..4c72d53 --- /dev/null +++ b/docs/examples/users/get-passkey.md @@ -0,0 +1,17 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +users = Users.new(client) + +result = users.get_passkey( + user_id: '', + passkey_id: '' +) +``` diff --git a/docs/examples/users/list-passkeys.md b/docs/examples/users/list-passkeys.md new file mode 100644 index 0000000..21faf80 --- /dev/null +++ b/docs/examples/users/list-passkeys.md @@ -0,0 +1,18 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +users = Users.new(client) + +result = users.list_passkeys( + user_id: '', + queries: [], # optional + total: false # optional +) +``` diff --git a/docs/examples/users/update-passkey.md b/docs/examples/users/update-passkey.md new file mode 100644 index 0000000..e367aa9 --- /dev/null +++ b/docs/examples/users/update-passkey.md @@ -0,0 +1,18 @@ +```ruby +require 'appwrite' + +include Appwrite + +client = Client.new + .set_endpoint('https://.cloud.appwrite.io/v1') # Your API Endpoint + .set_project('') # Your project ID + .set_key('') # Your secret API key + +users = Users.new(client) + +result = users.update_passkey( + user_id: '', + passkey_id: '', + name: '' +) +``` diff --git a/lib/appwrite.rb b/lib/appwrite.rb index 6e6c992..d0f0af0 100644 --- a/lib/appwrite.rb +++ b/lib/appwrite.rb @@ -222,6 +222,10 @@ require_relative 'appwrite/models/email_template' require_relative 'appwrite/models/mfa_challenge' require_relative 'appwrite/models/mfa_challenge_secret' +require_relative 'appwrite/models/token_secret' +require_relative 'appwrite/models/passkey' +require_relative 'appwrite/models/passkey_challenge' +require_relative 'appwrite/models/passkey_list' require_relative 'appwrite/models/mfa_recovery_codes' require_relative 'appwrite/models/mfa_type' require_relative 'appwrite/models/mfa_factors' diff --git a/lib/appwrite/client.rb b/lib/appwrite/client.rb index 63fb784..095947c 100644 --- a/lib/appwrite/client.rb +++ b/lib/appwrite/client.rb @@ -14,7 +14,7 @@ def initialize 'x-sdk-name' => 'Ruby', 'x-sdk-platform' => 'server', 'x-sdk-language' => 'ruby', - 'x-sdk-version' => '28.2.0', + 'x-sdk-version' => '28.3.0', 'X-Appwrite-Response-Format' => '2.0.0' } @endpoint = 'https://cloud.appwrite.io/v1' diff --git a/lib/appwrite/models/passkey.rb b/lib/appwrite/models/passkey.rb new file mode 100644 index 0000000..5098b87 --- /dev/null +++ b/lib/appwrite/models/passkey.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Appwrite + module Models + class Passkey + attr_reader :id + attr_reader :created_at + attr_reader :updated_at + attr_reader :name + attr_reader :accessed_at + + def initialize( + id:, + created_at:, + updated_at:, + name:, + accessed_at: + ) + @id = id + @created_at = created_at + @updated_at = updated_at + @name = name + @accessed_at = accessed_at + end + + def self.from(map:) + Passkey.new( + id: map["$id"], + created_at: map["$createdAt"], + updated_at: map["$updatedAt"], + name: map["name"], + accessed_at: map["accessedAt"] + ) + end + + def to_map + { + "$id": @id, + "$createdAt": @created_at, + "$updatedAt": @updated_at, + "name": @name, + "accessedAt": @accessed_at + } + end + end + end +end diff --git a/lib/appwrite/models/passkey_challenge.rb b/lib/appwrite/models/passkey_challenge.rb new file mode 100644 index 0000000..b975118 --- /dev/null +++ b/lib/appwrite/models/passkey_challenge.rb @@ -0,0 +1,47 @@ +# frozen_string_literal: true + +module Appwrite + module Models + class PasskeyChallenge + attr_reader :id + attr_reader :created_at + attr_reader :passkey_id + attr_reader :expire + attr_reader :public_key + + def initialize( + id:, + created_at:, + passkey_id:, + expire:, + public_key: + ) + @id = id + @created_at = created_at + @passkey_id = passkey_id + @expire = expire + @public_key = public_key + end + + def self.from(map:) + PasskeyChallenge.new( + id: map["$id"], + created_at: map["$createdAt"], + passkey_id: map["passkeyId"], + expire: map["expire"], + public_key: map["publicKey"] + ) + end + + def to_map + { + "$id": @id, + "$createdAt": @created_at, + "passkeyId": @passkey_id, + "expire": @expire, + "publicKey": @public_key + } + end + end + end +end diff --git a/lib/appwrite/models/passkey_list.rb b/lib/appwrite/models/passkey_list.rb new file mode 100644 index 0000000..86a515b --- /dev/null +++ b/lib/appwrite/models/passkey_list.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Appwrite + module Models + class PasskeyList + attr_reader :total + attr_reader :passkeys + + def initialize( + total:, + passkeys: + ) + @total = total + @passkeys = passkeys + end + + def self.from(map:) + PasskeyList.new( + total: map["total"], + passkeys: map["passkeys"].map { |it| Passkey.from(map: it) } + ) + end + + def to_map + { + "total": @total, + "passkeys": @passkeys.map { |it| it.to_map } + } + end + end + end +end diff --git a/lib/appwrite/models/token_secret.rb b/lib/appwrite/models/token_secret.rb new file mode 100644 index 0000000..4744532 --- /dev/null +++ b/lib/appwrite/models/token_secret.rb @@ -0,0 +1,52 @@ +# frozen_string_literal: true + +module Appwrite + module Models + class TokenSecret + attr_reader :id + attr_reader :created_at + attr_reader :user_id + attr_reader :secret + attr_reader :expire + attr_reader :phrase + + def initialize( + id:, + created_at:, + user_id:, + secret:, + expire:, + phrase: + ) + @id = id + @created_at = created_at + @user_id = user_id + @secret = secret + @expire = expire + @phrase = phrase + end + + def self.from(map:) + TokenSecret.new( + id: map["$id"], + created_at: map["$createdAt"], + user_id: map["userId"], + secret: map["secret"], + expire: map["expire"], + phrase: map["phrase"] + ) + end + + def to_map + { + "$id": @id, + "$createdAt": @created_at, + "userId": @user_id, + "secret": @secret, + "expire": @expire, + "phrase": @phrase + } + end + end + end +end diff --git a/lib/appwrite/services/account.rb b/lib/appwrite/services/account.rb index 4d8bceb..e29464c 100644 --- a/lib/appwrite/services/account.rb +++ b/lib/appwrite/services/account.rb @@ -797,6 +797,226 @@ def update_name( ) end + # Get the list of verified passkeys registered by the currently logged in + # user. + # + # @param [Array] queries Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + # @param [] total When set to false, the total count returned will be 0 and will not be calculated. + # + # @return [PasskeyList] + def list_passkeys( + queries: nil, + total: nil + ) + api_path = '/account/passkeys' + + api_params = { + queries: queries, + total: total, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "accept": 'application/json', + } + + @client.call( + method: 'GET', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::PasskeyList + ) + end + + # Start registering a passkey for the currently logged in user. The session + # must have signed in or completed an MFA challenge within the last 10 + # minutes. Pass the returned `publicKey` options to + # `navigator.credentials.create()`, then complete the registration with + # [Update passkey + # verification](/docs/references/cloud/client-web/account#updatePasskeyVerification). + # The passkey stays pending until verified, and the challenge expires after 5 + # minutes. + # + # @param [String] passkey_id Passkey ID. Choose a custom ID or generate a random ID with `ID.unique()`. Valid chars are a-z, A-Z, 0-9, period, hyphen, and underscore. Can't start with a special char. Max length is 36 chars. + # @param [String] name Passkey name, shown when listing passkeys. Max length: 128 chars. + # + # @return [PasskeyChallenge] + def create_passkey( + passkey_id: nil, + name: nil + ) + api_path = '/account/passkeys' + + api_params = { + passkeyId: passkey_id, + name: name, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'POST', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::PasskeyChallenge + ) + end + + # Get a verified passkey of the currently logged in user by its unique ID. + # + # @param [String] passkey_id Passkey ID. + # + # @return [Passkey] + def get_passkey( + passkey_id: + ) + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + api_path = '/account/passkeys/{passkeyId}' + .gsub('{passkeyId}', passkey_id) + + api_params = {} + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "accept": 'application/json', + } + + @client.call( + method: 'GET', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Passkey + ) + end + + # Rename a passkey of the currently logged in user. + # + # @param [String] passkey_id Passkey ID. + # @param [String] name Passkey name. Max length: 128 chars. + # + # @return [Passkey] + def update_passkey( + passkey_id:, + name: + ) + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + if name.nil? + raise Appwrite::Exception.new('Missing required parameter: "name"') + end + + api_path = '/account/passkeys/{passkeyId}' + .gsub('{passkeyId}', passkey_id) + + api_params = { + name: name, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'PATCH', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Passkey + ) + end + + # Delete a passkey from the currently logged in user. The passkey can no + # longer be used to sign in, although it may remain stored on the user's + # device. The session must have signed in or completed an MFA challenge + # within the last 10 minutes. + # + # @param [String] passkey_id Passkey ID. + # + # @return [] + def delete_passkey( + passkey_id: + ) + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + api_path = '/account/passkeys/{passkeyId}' + .gsub('{passkeyId}', passkey_id) + + api_params = {} + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'DELETE', + path: api_path, + headers: api_headers, + params: api_params, + ) + end + + # Complete a passkey registration started with [Create + # passkey](/docs/references/cloud/client-web/account#createPasskey). Pass the + # JSON form of the credential returned by `navigator.credentials.create()`, + # for example `credential.toJSON()`. Each registration can be verified once; + # a failed attempt requires starting it again. + # + # @param [String] passkey_id Passkey ID. + # @param [Hash] credential Registration credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + # + # @return [Passkey] + def update_passkey_verification( + passkey_id:, + credential: + ) + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + if credential.nil? + raise Appwrite::Exception.new('Missing required parameter: "credential"') + end + + api_path = '/account/passkeys/{passkeyId}/verification' + .gsub('{passkeyId}', passkey_id) + + api_params = { + credential: credential, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'PUT', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Passkey + ) + end + # Update currently logged in user password. For validation, user is required # to pass in the new password, and the old password. For users created with # OAuth, Team Invites and Magic URL, oldPassword is optional. @@ -1592,6 +1812,84 @@ def create_o_auth2_token( ) end + # Start signing in with a passkey. No email or user ID is needed: pass the + # returned `publicKey` options to `navigator.credentials.get()` and the user + # picks one of their passkeys. Then call [Update passkey + # token](/docs/references/cloud/client-web/account#updatePasskeyToken) with + # the credential to receive a token, and exchange it with [Create + # session](/docs/references/cloud/client-web/account#createSession). The + # challenge expires after 5 minutes. + # + # + # @return [PasskeyChallenge] + def create_passkey_token() + api_path = '/account/tokens/passkey' + + api_params = {} + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'POST', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::PasskeyChallenge + ) + end + + # Complete a passkey sign-in started with [Create passkey + # token](/docs/references/cloud/client-web/account#createPasskeyToken). Pass + # the challenge ID and the JSON form of the credential returned by + # `navigator.credentials.get()`, for example `credential.toJSON()`. The + # returned token includes its secret and expires after 1 minute: exchange it + # for a session with [Create + # session](/docs/references/cloud/client-web/account#createSession). Passkeys + # require user verification, so the session also satisfies MFA. Each + # challenge can only be used once. + # + # @param [String] challenge_id Challenge ID returned by createPasskeyToken. + # @param [Hash] credential Authentication credential returned by the authenticator, in the JSON form produced by `PublicKeyCredential.toJSON()`. + # + # @return [TokenSecret] + def update_passkey_token( + challenge_id:, + credential: + ) + if challenge_id.nil? + raise Appwrite::Exception.new('Missing required parameter: "challengeId"') + end + + if credential.nil? + raise Appwrite::Exception.new('Missing required parameter: "credential"') + end + + api_path = '/account/tokens/passkey' + + api_params = { + challengeId: challenge_id, + credential: credential, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'PUT', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::TokenSecret + ) + end + # Sends the user an SMS with a secret key for creating a session. If the # provided user ID has not be registered, a new user will be created. Use the # returned user ID and secret and submit a request to the [POST diff --git a/lib/appwrite/services/project.rb b/lib/appwrite/services/project.rb index 6235af2..0d4f9f5 100644 --- a/lib/appwrite/services/project.rb +++ b/lib/appwrite/services/project.rb @@ -3386,6 +3386,44 @@ def update_mfa_factors_policy( ) end + # Set the relying party ID passkeys are bound to: the domain of your + # application. Passkeys work on the project's web platforms on that domain or + # its subdomains, and on the domain itself for Apple apps. A localhost web + # platform enables passkeys for local development without a relying party ID. + # The relying party ID cannot change while users have passkeys, and any + # change invalidates ceremonies in progress. + # + # @param [String] rp_id Relying party ID: the domain of your application, such as `example.com`. Use `localhost` for local development, or an empty string to unset it. + # + # @return [Project] + def update_passkey_policy( + rp_id: + ) + if rp_id.nil? + raise Appwrite::Exception.new('Missing required parameter: "rpId"') + end + + api_path = '/project/policies/passkey' + + api_params = { + rpId: rp_id, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'PATCH', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Project + ) + end + # Updating this policy allows you to control if new passwords are checked # against most common passwords dictionary. When enabled, and user changes # their password, password must not be contained in the dictionary. diff --git a/lib/appwrite/services/users.rb b/lib/appwrite/services/users.rb index 86f5483..aefa1b2 100644 --- a/lib/appwrite/services/users.rb +++ b/lib/appwrite/services/users.rb @@ -1188,6 +1188,168 @@ def update_name( ) end + # Get the list of verified passkeys registered by a user. + # + # @param [String] user_id User ID. + # @param [Array] queries Array of query strings generated using the Query class provided by the SDK. [Learn more about queries](https://appwrite.io/docs/queries). Maximum of 100 queries are allowed, each 4096 characters long. You may filter and order on the following attributes: $id, $createdAt, $updatedAt, name, accessedAt + # @param [] total When set to false, the total count returned will be 0 and will not be calculated. + # + # @return [PasskeyList] + def list_passkeys( + user_id:, + queries: nil, + total: nil + ) + if user_id.nil? || user_id == '' + raise Appwrite::Exception.new('Missing required parameter: "userId"') + end + + api_path = '/users/{userId}/passkeys' + .gsub('{userId}', user_id) + + api_params = { + queries: queries, + total: total, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "accept": 'application/json', + } + + @client.call( + method: 'GET', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::PasskeyList + ) + end + + # Get a verified passkey of a user by its unique ID. + # + # @param [String] user_id User ID. + # @param [String] passkey_id Passkey ID. + # + # @return [Passkey] + def get_passkey( + user_id:, + passkey_id: + ) + if user_id.nil? || user_id == '' + raise Appwrite::Exception.new('Missing required parameter: "userId"') + end + + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + api_path = '/users/{userId}/passkeys/{passkeyId}' + .gsub('{userId}', user_id) + .gsub('{passkeyId}', passkey_id) + + api_params = {} + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "accept": 'application/json', + } + + @client.call( + method: 'GET', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Passkey + ) + end + + # Rename a passkey of a user. + # + # @param [String] user_id User ID. + # @param [String] passkey_id Passkey ID. + # @param [String] name Passkey name. Max length: 128 chars. + # + # @return [Passkey] + def update_passkey( + user_id:, + passkey_id:, + name: + ) + if user_id.nil? || user_id == '' + raise Appwrite::Exception.new('Missing required parameter: "userId"') + end + + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + if name.nil? + raise Appwrite::Exception.new('Missing required parameter: "name"') + end + + api_path = '/users/{userId}/passkeys/{passkeyId}' + .gsub('{userId}', user_id) + .gsub('{passkeyId}', passkey_id) + + api_params = { + name: name, + } + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'PATCH', + path: api_path, + headers: api_headers, + params: api_params, + response_type: Models::Passkey + ) + end + + # Delete a passkey from a user, for example when a device is lost. The + # passkey can no longer be used to sign in. + # + # @param [String] user_id User ID. + # @param [String] passkey_id Passkey ID. + # + # @return [] + def delete_passkey( + user_id:, + passkey_id: + ) + if user_id.nil? || user_id == '' + raise Appwrite::Exception.new('Missing required parameter: "userId"') + end + + if passkey_id.nil? || passkey_id == '' + raise Appwrite::Exception.new('Missing required parameter: "passkeyId"') + end + + api_path = '/users/{userId}/passkeys/{passkeyId}' + .gsub('{userId}', user_id) + .gsub('{passkeyId}', passkey_id) + + api_params = {} + + api_headers = { + "X-Appwrite-Project": @client.get_config('project'), + "content-type": 'application/json', + "accept": 'application/json', + } + + @client.call( + method: 'DELETE', + path: api_path, + headers: api_headers, + params: api_params, + ) + end + # Update the user password by its unique ID. # # @param [String] user_id User ID.