diff --git a/dev/doc-import-tool/src/index.ts b/dev/doc-import-tool/src/index.ts index 233257cf99..097fb81e9b 100644 --- a/dev/doc-import-tool/src/index.ts +++ b/dev/doc-import-tool/src/index.ts @@ -62,6 +62,7 @@ export function docImportTool (): void { setMetadata(serverClientPlugin.metadata.Endpoint, accountUrl) setMetadata(serverToken.metadata.Secret, serverSecret) + setMetadata(serverToken.metadata.Service, process.env.SERVICE_ID ?? 'doc-import-tool') async function withStorage (f: (storageAdapter: StorageAdapter) => Promise): Promise { const adapter = buildStorageFromConfig(storageConfigFromEnv()) diff --git a/dev/tool/src/index.ts b/dev/tool/src/index.ts index 6aa8d57113..eb8ba864f8 100644 --- a/dev/tool/src/index.ts +++ b/dev/tool/src/index.ts @@ -187,6 +187,7 @@ export function devTool ( setMetadata(accountPlugin.metadata.Transactors, transactorUrl) setMetadata(serverClientPlugin.metadata.Endpoint, accountsUrl) setMetadata(serverToken.metadata.Secret, serverSecret) + setMetadata(serverToken.metadata.Service, 'tool') async function withAccountDatabase ( f: (db: AccountDB) => Promise, diff --git a/pods/fulltext/src/index.ts b/pods/fulltext/src/index.ts index 17a2998f12..f669ee64b2 100644 --- a/pods/fulltext/src/index.ts +++ b/pods/fulltext/src/index.ts @@ -37,6 +37,7 @@ if (serverSecret === undefined) { } setMetadata(serverToken.metadata.Secret, serverSecret) +setMetadata(serverToken.metadata.Service, 'fulltext') const metricsContext = initStatisticsContext('fulltext', { factory: () => diff --git a/pods/fulltext/src/server.ts b/pods/fulltext/src/server.ts index 0e355e32d2..07e7bffcce 100644 --- a/pods/fulltext/src/server.ts +++ b/pods/fulltext/src/server.ts @@ -99,6 +99,7 @@ export async function startIndexer ( }) setMetadata(serverToken.metadata.Secret, opt.serverSecret) + setMetadata(serverToken.metadata.Service, 'fulltext') setMetadata(serverCore.metadata.ElasticIndexName, opt.elasticIndexName) setMetadata(serverClientPlugin.metadata.Endpoint, opt.accountsUrl) diff --git a/pods/media/src/index.ts b/pods/media/src/index.ts index 8f1b3a31ff..d116238b00 100644 --- a/pods/media/src/index.ts +++ b/pods/media/src/index.ts @@ -32,6 +32,7 @@ const topicTranscodeResult = 'stream.transcode.result' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'media') } async function main (): Promise { diff --git a/pods/server/src/__start.ts b/pods/server/src/__start.ts index 507a70f579..0a77736523 100644 --- a/pods/server/src/__start.ts +++ b/pods/server/src/__start.ts @@ -78,6 +78,7 @@ setMetadata(contactPlugin.metadata.LastNameFirst, lastNameFirst) setMetadata(serverCore.metadata.FrontUrl, config.frontUrl) setMetadata(serverCore.metadata.FilesUrl, config.filesUrl) setMetadata(serverToken.metadata.Secret, config.serverSecret) +setMetadata(serverToken.metadata.Service, 'transactor') setMetadata(serverNotification.metadata.MailUrl, config.mailUrl ?? '') setMetadata(serverNotification.metadata.MailAuthToken, config.mailAuthToken) setMetadata(serverNotification.metadata.WebPushUrl, config.webPushUrl) diff --git a/pods/stats/src/stats.ts b/pods/stats/src/stats.ts index 438863bab7..2c2bde6c54 100644 --- a/pods/stats/src/stats.ts +++ b/pods/stats/src/stats.ts @@ -59,6 +59,7 @@ export function serveStats (ctx: MeasureContext, onClose?: () => void): void { } setMetadata(serverToken.metadata.Secret, serverSecret) + setMetadata(serverToken.metadata.Service, 'stats') const statistics = new Map() const timeouts = new Map() diff --git a/server/account-service/src/index.ts b/server/account-service/src/index.ts index 1839dba90d..c439ac065a 100644 --- a/server/account-service/src/index.ts +++ b/server/account-service/src/index.ts @@ -105,6 +105,7 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap setMetadata(account.metadata.WsLivenessDays, wsLivenessDays) setMetadata(serverToken.metadata.Secret, serverSecret) + setMetadata(serverToken.metadata.Service, 'account') const hasSignUp = process.env.DISABLE_SIGNUP !== 'true' const methods = getMethods(hasSignUp) diff --git a/server/backup-service/src/index.ts b/server/backup-service/src/index.ts index b4c12d69e4..d0f59eede5 100644 --- a/server/backup-service/src/index.ts +++ b/server/backup-service/src/index.ts @@ -40,6 +40,7 @@ export function startBackup ( ): void { const config = _config() setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'backup') setMetadata(serverClientPlugin.metadata.Endpoint, config.AccountsURL) setMetadata(serverClientPlugin.metadata.UserAgent, config.ServiceID) @@ -97,6 +98,7 @@ export async function backupWorkspace ( ): Promise { const config = _config() setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'backup') setMetadata(serverClientPlugin.metadata.Endpoint, config.AccountsURL) setMetadata(serverClientPlugin.metadata.UserAgent, config.ServiceID) diff --git a/server/collaborator/src/starter.ts b/server/collaborator/src/starter.ts index a403e16674..78b6eca863 100644 --- a/server/collaborator/src/starter.ts +++ b/server/collaborator/src/starter.ts @@ -26,6 +26,7 @@ import { start } from './server' export async function startCollaborator (ctx: MeasureContext, onClose?: () => void): Promise { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'collaborator') setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) diff --git a/server/datalake/src/index.ts b/server/datalake/src/index.ts index 63fbc13700..321b20270e 100644 --- a/server/datalake/src/index.ts +++ b/server/datalake/src/index.ts @@ -79,7 +79,7 @@ export class DatalakeService implements StorageAdapter { if (secret === undefined) { console.warn('Server secret not set, datalake storage adapter initialized with default secret') } - const token = generateToken(systemAccountUuid, undefined, { service: 'datalake' }) + const token = generateToken(systemAccountUuid, undefined) this.client = createDatalakeClient(cfg, token) this.retryCount = options.retryCount ?? 5 this.retryInterval = options.retryInterval ?? 50 diff --git a/server/front/src/starter.ts b/server/front/src/starter.ts index 02b21642aa..ad255bae82 100644 --- a/server/front/src/starter.ts +++ b/server/front/src/starter.ts @@ -121,6 +121,7 @@ export function startFront (ctx: MeasureContext, extraConfig?: Record { + beforeEach(() => { + setMetadata(plugin.metadata.Secret, undefined) + setMetadata(plugin.metadata.Service, undefined) + }) + it('throws TokenError for invalid account uuid', () => { expect(() => { generateToken('invalid-uuid' as PersonUuid, '' as WorkspaceUuid, {}, 'secret') @@ -76,4 +83,34 @@ describe('generateToken', () => { workspace: '123e4567-e89b-12d3-a456-426614174001' }) }) + + it('should generate token with default secret', () => { + const token = generateToken( + '123e4567-e89b-12d3-a456-426614174000' as PersonUuid, + '123e4567-e89b-12d3-a456-426614174001' as WorkspaceUuid, + undefined, + 'test' + ) + const decodedPayload = decodeTokenPayload(token) + expect(decodedPayload).toEqual({ + account: '123e4567-e89b-12d3-a456-426614174000', + workspace: '123e4567-e89b-12d3-a456-426614174001' + }) + }) + + it('should generate token with default service in extra', () => { + setMetadata(plugin.metadata.Service, 'test') + const token = generateToken( + '123e4567-e89b-12d3-a456-426614174000' as PersonUuid, + '123e4567-e89b-12d3-a456-426614174001' as WorkspaceUuid, + undefined, + 'secret' + ) + const decodedPayload = decodeToken(token, false, 'test') + expect(decodedPayload).toEqual({ + extra: { service: 'test' }, + account: '123e4567-e89b-12d3-a456-426614174000', + workspace: '123e4567-e89b-12d3-a456-426614174001' + }) + }) }) diff --git a/server/token/src/plugin.ts b/server/token/src/plugin.ts index ddbd2f8901..67a8f57976 100644 --- a/server/token/src/plugin.ts +++ b/server/token/src/plugin.ts @@ -26,7 +26,8 @@ export const serverTokenId = 'server-token' as Plugin */ const serverToken = plugin(serverTokenId, { metadata: { - Secret: '' as Metadata + Secret: '' as Metadata, + Service: '' as Metadata } }) diff --git a/server/token/src/token.ts b/server/token/src/token.ts index 6659acdb75..63550acc73 100644 --- a/server/token/src/token.ts +++ b/server/token/src/token.ts @@ -43,6 +43,11 @@ export function generateToken ( throw new TokenError(`Invalid workspace uuid: "${workspaceUuid}"`) } + const service = getMetadata(serverPlugin.metadata.Service) + if (service !== undefined) { + extra = { service, ...extra } + } + return encode( { ...(extra !== undefined ? { extra } : {}), account: accountUuid, workspace: workspaceUuid }, secret ?? getSecret() diff --git a/server/workspace-service/src/index.ts b/server/workspace-service/src/index.ts index 9c1cf558cc..77d9070ef1 100644 --- a/server/workspace-service/src/index.ts +++ b/server/workspace-service/src/index.ts @@ -104,6 +104,7 @@ export function serveWorkspaceAccount ( const waitTimeout = parseInt(process.env.WAIT_TIMEOUT ?? '5000') setMetadata(serverToken.metadata.Secret, serverSecret) + setMetadata(serverToken.metadata.Service, 'workspace') const initWS = process.env.INIT_WORKSPACE if (initWS !== undefined) { diff --git a/services/ai-bot/pod-ai-bot/src/start.ts b/services/ai-bot/pod-ai-bot/src/start.ts index 71ed6c24ea..8185dbf716 100644 --- a/services/ai-bot/pod-ai-bot/src/start.ts +++ b/services/ai-bot/pod-ai-bot/src/start.ts @@ -30,6 +30,7 @@ import { getAccountUuid } from './utils/account' export const start = async (): Promise => { setMetadata(serverToken.metadata.Secret, config.ServerSecret) + setMetadata(serverToken.metadata.Service, 'ai-bot-service') setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) diff --git a/services/backup/backup-api-pod/src/main.ts b/services/backup/backup-api-pod/src/main.ts index 1eca4edabb..01c57b1929 100644 --- a/services/backup/backup-api-pod/src/main.ts +++ b/services/backup/backup-api-pod/src/main.ts @@ -26,6 +26,7 @@ import { createServer, listen } from './server' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'backup-api') } export const main = async (): Promise => { diff --git a/services/billing/pod-billing/src/main.ts b/services/billing/pod-billing/src/main.ts index fcd4ba3542..782fd4e446 100644 --- a/services/billing/pod-billing/src/main.ts +++ b/services/billing/pod-billing/src/main.ts @@ -26,6 +26,7 @@ import serverToken from '@hcengineering/server-token' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'billing') setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) } diff --git a/services/calendar/pod-calendar-mailer/src/index.ts b/services/calendar/pod-calendar-mailer/src/index.ts index b1de45c166..28a63a8766 100644 --- a/services/calendar/pod-calendar-mailer/src/index.ts +++ b/services/calendar/pod-calendar-mailer/src/index.ts @@ -41,8 +41,9 @@ async function main (): Promise { }) configureAnalytics(config.sentryDSN, config) - Analytics.setTag('application', 'telegram-bot-service') + Analytics.setTag('application', 'calendar-mailer') setMetadata(serverToken.metadata.Secret, config.secret) + setMetadata(serverToken.metadata.Service, 'calendar-mailer') const queue = getPlatformQueue('calendarMailerService', config.queueRegion) diff --git a/services/calendar/pod-calendar/src/main.ts b/services/calendar/pod-calendar/src/main.ts index 4044e225ff..52e8f25397 100644 --- a/services/calendar/pod-calendar/src/main.ts +++ b/services/calendar/pod-calendar/src/main.ts @@ -58,6 +58,7 @@ export const main = async (): Promise => { setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'calendar') const accountClient = getAccountClient(getServiceToken()) diff --git a/services/datalake/pod-datalake/src/main.ts b/services/datalake/pod-datalake/src/main.ts index 01569229b1..f20822da52 100644 --- a/services/datalake/pod-datalake/src/main.ts +++ b/services/datalake/pod-datalake/src/main.ts @@ -27,6 +27,7 @@ import { createServer, listen } from './server' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'datalake') } export const main = async (): Promise => { diff --git a/services/datalake/pod-datalake/src/middleware.ts b/services/datalake/pod-datalake/src/middleware.ts index 1f476d8c51..6a6574fb40 100644 --- a/services/datalake/pod-datalake/src/middleware.ts +++ b/services/datalake/pod-datalake/src/middleware.ts @@ -24,7 +24,7 @@ export interface KeepAliveOptions { max: number } -interface RequestWithAuth extends Request { +export interface RequestWithAuth extends Request { token?: Token } diff --git a/services/datalake/pod-datalake/src/server.ts b/services/datalake/pod-datalake/src/server.ts index 06942726c6..089527e225 100644 --- a/services/datalake/pod-datalake/src/server.ts +++ b/services/datalake/pod-datalake/src/server.ts @@ -19,7 +19,7 @@ import { PlatformQueue, QueueTopic, getCPUInfo, getMemoryInfo } from '@hcenginee import { decodeToken, TokenError } from '@hcengineering/server-token' import cors from 'cors' -import express, { type Express, type NextFunction, type Request, type Response } from 'express' +import express, { type Express, type NextFunction, type Response } from 'express' import fileUpload from 'express-fileupload' import { type Server } from 'http' import morgan from 'morgan' @@ -29,6 +29,7 @@ import { cacheControl } from './const' import { createDb } from './datalake/db' import { ApiError } from './error' import { + type RequestWithAuth, keepAlive, withAdminAuthorization, withAuthorization, @@ -69,7 +70,7 @@ const cacheControlNoCache = 'public, no-store, no-cache, must-revalidate, max-ag type AsyncRequestHandler = ( ctx: MeasureContext, - req: Request, + req: RequestWithAuth, res: Response, datalake: Datalake, tempDir: TemporaryDir @@ -81,12 +82,13 @@ const handleRequest = async ( datalake: Datalake, tempDir: TemporaryDir, fn: AsyncRequestHandler, - req: Request, + req: RequestWithAuth, res: Response, next: NextFunction ): Promise => { try { - await ctx.with(name, {}, (ctx) => { + const source = req.token?.extra?.service ?? '🤦‍♂️user' + await ctx.with(name, { source }, (ctx) => { onHeaders(res, () => { const measurements = ctx.metrics?.measurements if (measurements !== undefined) { @@ -152,7 +154,7 @@ export async function createServer ( const wrapRequest = (ctx: MeasureContext, name: string, fn: AsyncRequestHandler) => - (req: Request, res: Response, next: NextFunction) => { + (req: RequestWithAuth, res: Response, next: NextFunction) => { // eslint-disable-next-line @typescript-eslint/no-floating-promises handleRequest(ctx, name, datalake, tempDir, fn, req, res, next) } diff --git a/services/export/pod-export/src/main.ts b/services/export/pod-export/src/main.ts index f7fbc465a3..f7a5996916 100644 --- a/services/export/pod-export/src/main.ts +++ b/services/export/pod-export/src/main.ts @@ -22,6 +22,7 @@ import { createServer, listen } from './server' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'export') setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) } diff --git a/services/github/pod-github/src/index.ts b/services/github/pod-github/src/index.ts index 7ea7f45d4c..9ce3e0167e 100644 --- a/services/github/pod-github/src/index.ts +++ b/services/github/pod-github/src/index.ts @@ -15,6 +15,7 @@ import serverToken from '@hcengineering/server-token' // Load and inc startID, to have easy logs. setMetadata(serverToken.metadata.Secret, config.ServerSecret) +setMetadata(serverToken.metadata.Service, 'github') const metricsContext = initStatisticsContext('github', { factory: () => diff --git a/services/gmail/pod-gmail/src/main.ts b/services/gmail/pod-gmail/src/main.ts index cbf3db624e..56f0d13db8 100644 --- a/services/gmail/pod-gmail/src/main.ts +++ b/services/gmail/pod-gmail/src/main.ts @@ -59,6 +59,7 @@ export const main = async (): Promise => { setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'gmail') const storageConfig: StorageConfiguration = storageConfigFromEnv() const storageAdapter = buildStorageFromConfig(storageConfig) diff --git a/services/love/src/main.ts b/services/love/src/main.ts index 8df729a667..c3a8b6b117 100644 --- a/services/love/src/main.ts +++ b/services/love/src/main.ts @@ -59,6 +59,7 @@ export const main = async (): Promise => { setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'love') const storageConfigs: StorageConfiguration = storageConfigFromEnv() const s3StorageConfigs: StorageConfiguration | undefined = diff --git a/services/mail/pod-inbound-mail/src/index.ts b/services/mail/pod-inbound-mail/src/index.ts index 2a4bd61d5a..3a81a54ecc 100644 --- a/services/mail/pod-inbound-mail/src/index.ts +++ b/services/mail/pod-inbound-mail/src/index.ts @@ -45,6 +45,7 @@ async function main (): Promise { }) setMetadata(serverToken.metadata.Secret, config.secret) + setMetadata(serverToken.metadata.Service, 'inbound-mail') initQueue(ctx, 'inbound-mail', baseConfig) diff --git a/services/msg2file/src/main.ts b/services/msg2file/src/main.ts index 1be72dec68..61cc89fd3c 100644 --- a/services/msg2file/src/main.ts +++ b/services/msg2file/src/main.ts @@ -29,6 +29,7 @@ export const main = async (): Promise => { setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'msg2file') const ctx = initStatisticsContext(config.ServiceID, {}) const storage = buildStorageFromConfig(storageConfigFromEnv()) diff --git a/services/print/pod-print/src/main.ts b/services/print/pod-print/src/main.ts index 5a6894a2d8..c0958d6c4d 100644 --- a/services/print/pod-print/src/main.ts +++ b/services/print/pod-print/src/main.ts @@ -11,6 +11,7 @@ import { createServer, listen } from './server' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'print') } export const main = async (): Promise => { diff --git a/services/rekoni/src/server.ts b/services/rekoni/src/server.ts index a3796ec56b..bc52eb0e51 100644 --- a/services/rekoni/src/server.ts +++ b/services/rekoni/src/server.ts @@ -48,6 +48,7 @@ export const startServer = async (): Promise => { const app = express() setMetadata(serverToken.metadata.Secret, process.env.SECRET) + setMetadata(serverToken.metadata.Service, 'rekoni') const ctx = initStatisticsContext('rekoni', { factory: () => new MeasureMetricsContext( diff --git a/services/sign/pod-sign/src/main.ts b/services/sign/pod-sign/src/main.ts index 0e2b6063c5..362723b653 100644 --- a/services/sign/pod-sign/src/main.ts +++ b/services/sign/pod-sign/src/main.ts @@ -13,6 +13,7 @@ import { createServer, listen } from './server' const setupMetadata = (): void => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'sign') setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) } diff --git a/services/telegram-bot/pod-telegram-bot/src/start.ts b/services/telegram-bot/pod-telegram-bot/src/start.ts index 41b72ba7e9..a0c1fe5314 100644 --- a/services/telegram-bot/pod-telegram-bot/src/start.ts +++ b/services/telegram-bot/pod-telegram-bot/src/start.ts @@ -49,6 +49,7 @@ Analytics.setTag('application', 'telegram-bot-service') export const start = async (): Promise => { setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'telegram-bot-service') setMetadata(serverClient.metadata.Endpoint, config.AccountsUrl) setMetadata(serverClient.metadata.UserAgent, config.ServiceId) registerLoaders() diff --git a/services/telegram/pod-telegram/src/main.ts b/services/telegram/pod-telegram/src/main.ts index 056cb85a43..9784378b34 100644 --- a/services/telegram/pod-telegram/src/main.ts +++ b/services/telegram/pod-telegram/src/main.ts @@ -43,6 +43,7 @@ export const main = async (): Promise => { setMetadata(serverClient.metadata.Endpoint, config.AccountsURL) setMetadata(serverClient.metadata.UserAgent, config.ServiceID) setMetadata(serverToken.metadata.Secret, config.Secret) + setMetadata(serverToken.metadata.Service, 'telegram') const storageConfig: StorageConfiguration = storageConfigFromEnv() const storageAdapter = buildStorageFromConfig(storageConfig)