UNPKG

@shogun-sdk/accounts

Version:

Shogun with Turnkey: configs, encryption, authentication with Telegram/Turnkey OIDC, etc.

192 lines 7.29 kB
import { ApiKeyStamper, DEFAULT_ETHEREUM_ACCOUNTS, DEFAULT_SOLANA_ACCOUNTS, TurnkeyServerClient, } from '@turnkey/sdk-server'; import { decode } from 'jsonwebtoken'; import { TURNKEY_APP_CONFIG } from '../config/index.js'; export const TURNKEY_SESSION_EXPIRE = '7200'; // 2 hours in seconds export const getTurnkeyConfig = (baseUrl, organizationId, rpId) => ({ apiBaseUrl: baseUrl, defaultOrganizationId: organizationId, rpId, iframeUrl: 'https://auth.turnkey.com', }); export const TURNKEY_EMBEDDED_KEY = "@turnkey/embedded_key"; export const TURNKEY_EMBEDDED_KEY_TTL_IN_MILLIS = 1000 * 60 * 60 * 24 * 365 * 10; // 10 years in milliseconds export const TURNKEY_CREDENTIAL_BUNDLE = "@turnkey/credential_bundle"; export const TURNKEY_CREDENTIAL_BUNDLE_TTL_IN_MILLIS = 1000 * 60 * 60 * 24 * 365 * 10; // 48 hours in milliseconds; export const getApiKeyStamper = (apiPublicKey, apiPrivateKey) => new ApiKeyStamper({ apiPublicKey, apiPrivateKey, }); const getTurnkeyClient = (baseUrl, organizationId, stamper) => new TurnkeyServerClient({ apiBaseUrl: baseUrl, organizationId, stamper, }); function decodeJwt(credential) { const decoded = decode(credential); if (decoded && typeof decoded === 'object' && 'email' in decoded) { return decoded; } return null; } export const oauth = async ({ credential, targetPublicKey, targetSubOrgId, config, stamper, }) => { const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const oauthResponse = await client.oauth({ oidcToken: credential, targetPublicKey, organizationId: targetSubOrgId, expirationSeconds: TURNKEY_SESSION_EXPIRE, }); return oauthResponse; }; export async function getSubOrgId(config, param, stamper) { let filterType; let filterValue; if ('userName' in param) { filterType = 'USERNAME'; filterValue = param.userName; } else if ('email' in param) { filterType = 'EMAIL'; filterValue = param.email; } else if ('publicKey' in param) { filterType = 'PUBLIC_KEY'; filterValue = param.publicKey; } else if ('oidcToken' in param) { filterType = 'OIDC_TOKEN'; filterValue = param.oidcToken; } else { throw new Error('Invalid parameter'); } const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const { organizationIds } = await client.getSubOrgIds({ organizationId: config.defaultOrganizationId, filterType, filterValue, }); return organizationIds[0]; } export const getSubOrgIdByEmail = async (config, email, stamper) => { return getSubOrgId(config, { email }, stamper); }; export const createUserSubOrg = async ({ config, username, email, passkey, oauth, delegationApiKey, onSuccess, stamper, }) => { const authenticators = passkey ? [ { authenticatorName: 'Passkey', challenge: passkey.challenge, attestation: passkey.attestation, }, ] : []; const oauthProviders = oauth ? [ { providerName: oauth.providerName, oidcToken: oauth.oidcToken, }, ] : []; let userEmail = email; // If the user is logging in with a Google Auth credential, use the email from the decoded OIDC token (credential // Otherwise, use the email from the email parameter if (oauth) { const decoded = decodeJwt(oauth.oidcToken); if (decoded?.email) { userEmail = decoded.email; } } const subOrganizationName = `Sub Org - ${email ?? ''}`; const userName = username ? username : email ? email.split('@')?.[0] || email : ''; const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const subOrg = await client.createSubOrganization({ organizationId: config.defaultOrganizationId, subOrganizationName, rootUsers: [ { userName, userEmail, oauthProviders, authenticators, apiKeys: delegationApiKey ? [{ apiKeyName: TURNKEY_APP_CONFIG.BOT_DELEGATION_NAME, publicKey: delegationApiKey, curveType: 'API_KEY_CURVE_P256', }] : [], }, ], rootQuorumThreshold: 1, wallet: { walletName: 'Default Wallet', accounts: [...DEFAULT_ETHEREUM_ACCOUNTS, ...DEFAULT_SOLANA_ACCOUNTS], }, }); const userId = subOrg.rootUserIds?.[0]; if (!userId) { throw new Error('No root user ID found'); } const { user } = await client.getUser({ organizationId: subOrg.subOrganizationId, userId, }); if (delegationApiKey && onSuccess) { await onSuccess?.(subOrg, delegationApiKey); } return { subOrg, user }; }; export const getSubOrgIdByPublicKey = async (config, publicKey, stamper) => { return getSubOrgId(config, { publicKey }, stamper); }; export const getSubOrgIdByUserName = async (config, userName, stamper) => { return getSubOrgId(config, { userName: userName.toLowerCase() }, stamper); }; export async function getWalletsWithAccounts(config, organizationId, stamper) { try { const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const { wallets } = await client.getWallets({ organizationId, }); const walletsWithAccounts = await Promise.all(wallets.map(async (wallet) => { try { const { accounts } = await client.getWalletAccounts({ organizationId, walletId: wallet.walletId, }); return { ...wallet, accounts }; } catch (error) { console.error(`Failed to fetch accounts for wallet ${wallet.walletId}:`, error); // Return wallet with empty accounts array if account fetch fails return { ...wallet, accounts: [] }; } })); return walletsWithAccounts; } catch (error) { console.error('Failed to fetch wallets:', error); throw new Error('Failed to fetch wallets and accounts. Please try again later.'); } } export async function getUserOrganization(config, organizationId, stamper) { const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const data = await client.getOrganization({ organizationId, }); return data; } export async function initEmailRecovery(config, organizationId, email, targetPublicKey, stamper) { const client = getTurnkeyClient(config.apiBaseUrl, config.defaultOrganizationId, stamper); const data = await client.initUserEmailRecovery({ organizationId, email: email, targetPublicKey: targetPublicKey, emailCustomization: { appName: 'Gun.fun', logoUrl: 'https://www.gun.fun/images/logo.svg', }, }); return data; } //# sourceMappingURL=turnkey.js.map