From 61334e6815651debd3d298d0fae533088ff2ff0a Mon Sep 17 00:00:00 2001 From: Hamish Peebles Date: Fri, 15 Nov 2024 15:14:28 +0000 Subject: [PATCH] Add the `BotCommand` access token type (#6830) --- backend/canisters/community/CHANGELOG.md | 1 + .../c2c_can_issue_access_token_for_channel.rs | 2 +- backend/canisters/group/CHANGELOG.md | 1 + .../src/queries/c2c_can_issue_access_token.rs | 2 +- .../canisters/local_user_index/CHANGELOG.md | 6 +++- .../impl/src/queries/access_token.rs | 17 ++++++++++- backend/canisters/user/CHANGELOG.md | 1 + .../src/queries/c2c_can_issue_access_token.rs | 5 +++- backend/libraries/types/src/access_tokens.rs | 13 ++++++++- backend/libraries/types/src/claims.rs | 12 +++++++- frontend/openchat-agent/src/typebox.ts | 29 +++++++++++++------ tsBindings/shared/AccessTokenType.ts | 3 +- tsBindings/shared/BotCommandArgs.ts | 6 ++++ tsBindings/types.d.ts | 2 ++ 14 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 tsBindings/shared/BotCommandArgs.ts diff --git a/backend/canisters/community/CHANGELOG.md b/backend/canisters/community/CHANGELOG.md index 936dfc8b84..2d41092db0 100644 --- a/backend/canisters/community/CHANGELOG.md +++ b/backend/canisters/community/CHANGELOG.md @@ -12,6 +12,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Reduce size of metrics in memory ([#6765](https://github.com/open-chat-labs/open-chat/pull/6765)) - Run cycles check (+ other background tasks) when executing timer jobs ([#6815](https://github.com/open-chat-labs/open-chat/pull/6815)) - Add cycles balance check to more timer jobs ([#6822](https://github.com/open-chat-labs/open-chat/pull/6822)) +- Add the `BotCommand` access token type ([#6830](https://github.com/open-chat-labs/open-chat/pull/6830)) ### Removed diff --git a/backend/canisters/community/impl/src/queries/c2c_can_issue_access_token_for_channel.rs b/backend/canisters/community/impl/src/queries/c2c_can_issue_access_token_for_channel.rs index b01a464ee8..4932c92108 100644 --- a/backend/canisters/community/impl/src/queries/c2c_can_issue_access_token_for_channel.rs +++ b/backend/canisters/community/impl/src/queries/c2c_can_issue_access_token_for_channel.rs @@ -24,7 +24,7 @@ fn c2c_can_issue_access_token_for_channel_impl(args: Args, state: &RuntimeState) AccessTokenType::StartVideoCallV2(vc) => { can_start_video_call(member, state.data.is_public, vc.call_type, &channel.chat) } - AccessTokenType::JoinVideoCall | AccessTokenType::MarkVideoCallAsEnded => true, + AccessTokenType::JoinVideoCall | AccessTokenType::MarkVideoCallAsEnded | AccessTokenType::BotCommand(_) => true, } } diff --git a/backend/canisters/group/CHANGELOG.md b/backend/canisters/group/CHANGELOG.md index 91a75c7f9b..44ec20f50f 100644 --- a/backend/canisters/group/CHANGELOG.md +++ b/backend/canisters/group/CHANGELOG.md @@ -9,6 +9,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ### Changed - Add cycles balance check to more timer jobs ([#6822](https://github.com/open-chat-labs/open-chat/pull/6822)) +- Add the `BotCommand` access token type ([#6830](https://github.com/open-chat-labs/open-chat/pull/6830)) ## [[2.0.1453](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1453-group)] - 2024-11-14 diff --git a/backend/canisters/group/impl/src/queries/c2c_can_issue_access_token.rs b/backend/canisters/group/impl/src/queries/c2c_can_issue_access_token.rs index a562984075..6aefca02ab 100644 --- a/backend/canisters/group/impl/src/queries/c2c_can_issue_access_token.rs +++ b/backend/canisters/group/impl/src/queries/c2c_can_issue_access_token.rs @@ -18,7 +18,7 @@ fn c2c_can_issue_access_token_impl(args: Args, state: &RuntimeState) -> bool { match args.access_type { AccessTokenType::StartVideoCallV2(vc) => can_start_video_call(member, vc.call_type, &state.data.chat), - AccessTokenType::JoinVideoCall | AccessTokenType::MarkVideoCallAsEnded => true, + AccessTokenType::JoinVideoCall | AccessTokenType::MarkVideoCallAsEnded | AccessTokenType::BotCommand(_) => true, } } diff --git a/backend/canisters/local_user_index/CHANGELOG.md b/backend/canisters/local_user_index/CHANGELOG.md index 3ba34e38e7..7fb9e704bc 100644 --- a/backend/canisters/local_user_index/CHANGELOG.md +++ b/backend/canisters/local_user_index/CHANGELOG.md @@ -6,13 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [unreleased] +### Changed + +- Add `BotApiCanister` to the canister state ([#6828](https://github.com/open-chat-labs/open-chat/pull/6828)) +- Add the `BotCommand` access token type ([#6830](https://github.com/open-chat-labs/open-chat/pull/6830)) + ## [[2.0.1454](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1454-local_user_index)] - 2024-11-14 ### Changed - Top up canisters which have fewer than `MIN_CYCLES_BALANCE` cycles ([#6819](https://github.com/open-chat-labs/open-chat/pull/6819)) - Reduce top up amount to 0.02T ([#6821](https://github.com/open-chat-labs/open-chat/pull/6821)) -- Add `BotApiCanister` to the canister state ([#6828](https://github.com/open-chat-labs/open-chat/pull/6828)) ## [[2.0.1447](https://github.com/open-chat-labs/open-chat/releases/tag/v2.0.1447-local_user_index)] - 2024-11-13 diff --git a/backend/canisters/local_user_index/impl/src/queries/access_token.rs b/backend/canisters/local_user_index/impl/src/queries/access_token.rs index 9751af5302..f81e6b8219 100644 --- a/backend/canisters/local_user_index/impl/src/queries/access_token.rs +++ b/backend/canisters/local_user_index/impl/src/queries/access_token.rs @@ -7,7 +7,10 @@ use local_user_index_canister::access_token::{Response::*, *}; use rand::rngs::StdRng; use rand::SeedableRng; use serde::Serialize; -use types::{AccessTokenType, ChannelId, Chat, ChatId, CommunityId, JoinOrEndVideoCallClaims, StartVideoCallClaims, UserId}; +use types::{ + AccessTokenType, BotCommandClaims, ChannelId, Chat, ChatId, CommunityId, JoinOrEndVideoCallClaims, StartVideoCallClaims, + UserId, +}; #[query(composite = true, guard = "caller_is_openchat_user", candid = true, msgpack = true)] #[trace] @@ -53,6 +56,18 @@ async fn access_token(args: Args) -> Response { }; build_token(args.token_type, custom_claims, state) } + AccessTokenType::BotCommand(bc) => { + let bot_api_gateway = state.data.internet_identity_canister_id; + let custom_claims = BotCommandClaims { + user_id: bc.user_id, + bot: bc.bot, + thread_root_message_index: bc.thread_root_message_index, + message_id: bc.message_id, + bot_api_gateway, + reply_url: format!("https://{bot_api_gateway}.icp0.io/call"), + }; + build_token(args.token_type, custom_claims, state) + } }) } diff --git a/backend/canisters/user/CHANGELOG.md b/backend/canisters/user/CHANGELOG.md index ef6a0b4004..4447244a20 100644 --- a/backend/canisters/user/CHANGELOG.md +++ b/backend/canisters/user/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Run cycles check (+ other background tasks) when executing timer jobs ([#6815](https://github.com/open-chat-labs/open-chat/pull/6815)) - Add cycles balance check to more timer jobs ([#6822](https://github.com/open-chat-labs/open-chat/pull/6822)) - Avoid iterating all events when migrating private replies after group import ([#6827](https://github.com/open-chat-labs/open-chat/pull/6827)) +- Add the `BotCommand` access token type ([#6830](https://github.com/open-chat-labs/open-chat/pull/6830)) ### Removed diff --git a/backend/canisters/user/impl/src/queries/c2c_can_issue_access_token.rs b/backend/canisters/user/impl/src/queries/c2c_can_issue_access_token.rs index 06978e692e..13666ce24b 100644 --- a/backend/canisters/user/impl/src/queries/c2c_can_issue_access_token.rs +++ b/backend/canisters/user/impl/src/queries/c2c_can_issue_access_token.rs @@ -16,6 +16,9 @@ fn c2c_can_issue_access_token_impl(args: Args, state: &RuntimeState) -> bool { } match args.access_type { - AccessTokenType::StartVideoCallV2(_) | AccessTokenType::JoinVideoCall | AccessTokenType::MarkVideoCallAsEnded => true, + AccessTokenType::StartVideoCallV2(_) + | AccessTokenType::JoinVideoCall + | AccessTokenType::MarkVideoCallAsEnded + | AccessTokenType::BotCommand(_) => true, } } diff --git a/backend/libraries/types/src/access_tokens.rs b/backend/libraries/types/src/access_tokens.rs index 277dd85095..2c8f8169ff 100644 --- a/backend/libraries/types/src/access_tokens.rs +++ b/backend/libraries/types/src/access_tokens.rs @@ -1,4 +1,4 @@ -use crate::VideoCallType; +use crate::{MessageId, MessageIndex, UserId, VideoCallType}; use candid::CandidType; use serde::{Deserialize, Serialize}; use ts_export::ts_export; @@ -9,6 +9,7 @@ pub enum AccessTokenType { StartVideoCallV2(VideoCallAccessTokenArgs), JoinVideoCall, MarkVideoCallAsEnded, + BotCommand(BotCommandArgs), } #[ts_export] @@ -17,12 +18,22 @@ pub struct VideoCallAccessTokenArgs { pub call_type: VideoCallType, } +#[ts_export] +#[derive(CandidType, Serialize, Deserialize, Debug, Clone)] +pub struct BotCommandArgs { + pub user_id: UserId, + pub bot: UserId, + pub thread_root_message_index: Option, + pub message_id: MessageId, +} + impl AccessTokenType { pub fn type_name(&self) -> &str { match self { AccessTokenType::StartVideoCallV2(_) => "StartVideoCall", AccessTokenType::JoinVideoCall => "JoinVideoCall", AccessTokenType::MarkVideoCallAsEnded => "MarkVideoCallAsEnded", + AccessTokenType::BotCommand(_) => "BotCommand", } } } diff --git a/backend/libraries/types/src/claims.rs b/backend/libraries/types/src/claims.rs index 02a39c4f3e..1a44d1c9bb 100644 --- a/backend/libraries/types/src/claims.rs +++ b/backend/libraries/types/src/claims.rs @@ -1,4 +1,4 @@ -use crate::{Chat, UserId, VideoCallType}; +use crate::{CanisterId, Chat, MessageId, MessageIndex, UserId, VideoCallType}; use serde::{Deserialize, Serialize}; #[derive(Serialize, Deserialize, Clone)] @@ -31,3 +31,13 @@ pub struct StartVideoCallClaims { pub call_type: VideoCallType, pub is_diamond: bool, } + +#[derive(Serialize, Deserialize)] +pub struct BotCommandClaims { + pub user_id: UserId, + pub bot: UserId, + pub thread_root_message_index: Option, + pub message_id: MessageId, + pub bot_api_gateway: CanisterId, + pub reply_url: String, +} diff --git a/frontend/openchat-agent/src/typebox.ts b/frontend/openchat-agent/src/typebox.ts index 6b92927b2c..99150bc28a 100644 --- a/frontend/openchat-agent/src/typebox.ts +++ b/frontend/openchat-agent/src/typebox.ts @@ -4208,15 +4208,6 @@ export const OptionUpdateOptionalMessagePermissions = Type.Union( { default: "NoChange" }, ); -export type AccessTokenType = Static; -export const AccessTokenType = Type.Union([ - Type.Object({ - StartVideoCallV2: VideoCallAccessTokenArgs, - }), - Type.Literal("JoinVideoCall"), - Type.Literal("MarkVideoCallAsEnded"), -]); - export type PendingCryptoTransactionICRC2 = Static; export const PendingCryptoTransactionICRC2 = Type.Object({ ledger: TSBytes, @@ -4526,6 +4517,14 @@ export const DiamondMembershipDetails = Type.Object({ subscription: DiamondMembershipSubscription, }); +export type BotCommandArgs = Static; +export const BotCommandArgs = Type.Object({ + user_id: UserId, + bot: UserId, + thread_root_message_index: Type.Optional(Type.Union([MessageIndex, Type.Undefined()])), + message_id: MessageId, +}); + export type MemberLeft = Static; export const MemberLeft = Type.Object({ user_id: UserId, @@ -6074,6 +6073,18 @@ export const GroupFrozen = Type.Object({ reason: Type.Optional(Type.Union([Type.String(), Type.Undefined()])), }); +export type AccessTokenType = Static; +export const AccessTokenType = Type.Union([ + Type.Object({ + StartVideoCallV2: VideoCallAccessTokenArgs, + }), + Type.Literal("JoinVideoCall"), + Type.Literal("MarkVideoCallAsEnded"), + Type.Object({ + BotCommand: BotCommandArgs, + }), +]); + export type FailedCryptoTransactionICRC2 = Static; export const FailedCryptoTransactionICRC2 = Type.Object({ ledger: TSBytes, diff --git a/tsBindings/shared/AccessTokenType.ts b/tsBindings/shared/AccessTokenType.ts index 126c246778..87975a13bc 100644 --- a/tsBindings/shared/AccessTokenType.ts +++ b/tsBindings/shared/AccessTokenType.ts @@ -1,4 +1,5 @@ // This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { BotCommandArgs } from "./BotCommandArgs"; import type { VideoCallAccessTokenArgs } from "./VideoCallAccessTokenArgs"; -export type AccessTokenType = { "StartVideoCallV2": VideoCallAccessTokenArgs } | "JoinVideoCall" | "MarkVideoCallAsEnded"; +export type AccessTokenType = { "StartVideoCallV2": VideoCallAccessTokenArgs } | "JoinVideoCall" | "MarkVideoCallAsEnded" | { "BotCommand": BotCommandArgs }; diff --git a/tsBindings/shared/BotCommandArgs.ts b/tsBindings/shared/BotCommandArgs.ts new file mode 100644 index 0000000000..ee55f6b588 --- /dev/null +++ b/tsBindings/shared/BotCommandArgs.ts @@ -0,0 +1,6 @@ +// This file was generated by [ts-rs](https://github.com/Aleph-Alpha/ts-rs). Do not edit this file manually. +import type { MessageId } from "./MessageId"; +import type { MessageIndex } from "./MessageIndex"; +import type { UserId } from "./UserId"; + +export type BotCommandArgs = { user_id: UserId, bot: UserId, thread_root_message_index?: MessageIndex | undefined, message_id: MessageId, }; diff --git a/tsBindings/types.d.ts b/tsBindings/types.d.ts index b0f6e07c06..6980e6d790 100644 --- a/tsBindings/types.d.ts +++ b/tsBindings/types.d.ts @@ -468,6 +468,7 @@ export type ThreadSummary = { participant_ids: Array, followed_by_me: bo export type OptionUpdateDocument = "NoChange" | "SetToNone" | { "SetToSome": Document }; export type SuspensionDetails = { reason: string, action: SuspensionAction, suspended_by: UserId, }; export type DiamondMembershipDetails = { expires_at: bigint, pay_in_chat: boolean, subscription: DiamondMembershipSubscription, }; +export type BotCommandArgs = { user_id: UserId, bot: UserId, thread_root_message_index?: MessageIndex | undefined, message_id: MessageId, }; export type MemberLeft = { user_id: UserId, }; export type UserGroupDetails = { user_group_id: number, name: string, members: Array, }; export type GroupIndexRecommendedGroupsArgs = { count: number, exclusions: Array, }; @@ -643,6 +644,7 @@ export type Tips = Array<[TSBytes, Array<[UserId, bigint]>]>; export type CallParticipant = { user_id: UserId, joined: bigint, }; export type PermissionsChanged = { old_permissions_v2: GroupPermissions, new_permissions_v2: GroupPermissions, changed_by: UserId, }; export type GroupFrozen = { frozen_by: UserId, reason?: string | undefined, }; +export type AccessTokenType = { "StartVideoCallV2": VideoCallAccessTokenArgs } | "JoinVideoCall" | "MarkVideoCallAsEnded" | { "BotCommand": BotCommandArgs }; export type FailedCryptoTransactionICRC2 = { ledger: TSBytes, token: Cryptocurrency, amount: bigint, fee: bigint, spender: UserId, from: CryptoAccountICRC1, to: CryptoAccountICRC1, memo?: TSBytes | undefined, created: bigint, error_message: string, }; export type Proposal = { "NNS": NnsProposal } | { "SNS": SnsProposal }; export type UsersInvited = { user_ids: Array, invited_by: UserId, };