QFix: Fix default timezone (#8547)

* QFix: Fix default timezone

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Clean up

Signed-off-by: Artem Savchenko <armisav@gmail.com>

* Potential fix for code scanning alert no. 165: Unvalidated dynamic method call

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
Signed-off-by: Artyom Savchenko <armisav@gmail.com>

---------

Signed-off-by: Artem Savchenko <armisav@gmail.com>
Signed-off-by: Artyom Savchenko <armisav@gmail.com>
Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
This commit is contained in:
Artyom Savchenko 2025-04-15 14:07:04 +07:00 committed by GitHub
parent d2603d8629
commit a8d6eaca92
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 15 additions and 12 deletions

View File

@ -221,7 +221,7 @@ class AccountClientImpl implements AccountClient {
private async _rpc<T>(request: Request): Promise<T> { private async _rpc<T>(request: Request): Promise<T> {
const timezone = getClientTimezone() const timezone = getClientTimezone()
const meta: Record<string, string> = timezone !== undefined ? { 'X-Timezone': timezone } : {} const meta: Record<string, string> = timezone !== undefined ? { 'x-timezone': timezone } : {}
const response = await fetch(this.url, { const response = await fetch(this.url, {
...this.request, ...this.request,
headers: { headers: {

View File

@ -4,6 +4,7 @@
import account, { import account, {
type AccountMethods, type AccountMethods,
type Meta,
EndpointKind, EndpointKind,
accountId, accountId,
getAccountDB, getAccountDB,
@ -173,6 +174,10 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap
return extractAuthorizationToken(headers) ?? extractCookieToken(headers) return extractAuthorizationToken(headers) ?? extractCookieToken(headers)
} }
const getRequestMeta = (headers: IncomingHttpHeaders): Meta => {
return headers?.['x-timezone'] !== undefined ? { timezone: headers['x-timezone'] as string } : {}
}
function getCookieOptions (ctx: Koa.Context): Cookies.SetOption { function getCookieOptions (ctx: Koa.Context): Cookies.SetOption {
const requestUrl = ctx.request.href const requestUrl = ctx.request.href
const url = new URL(requestUrl) const url = new URL(requestUrl)
@ -314,6 +319,7 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap
router.post('rpc', '/', async (ctx) => { router.post('rpc', '/', async (ctx) => {
const token = extractToken(ctx.request.headers) const token = extractToken(ctx.request.headers)
const meta = getRequestMeta(ctx.request.headers)
const request = ctx.request.body as any const request = ctx.request.body as any
const method = methods[request.method as AccountMethods] const method = methods[request.method as AccountMethods]
@ -339,7 +345,7 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap
} }
const branding = host !== undefined ? brandings[host] : null const branding = host !== undefined ? brandings[host] : null
const result = await measureCtx.with(request.method, {}, (mctx) => { const result = await measureCtx.with(request.method, {}, (mctx) => {
if (method === undefined) { if (method === undefined || typeof method !== 'function') {
const response = { const response = {
id: request.id, id: request.id,
error: new Status(Severity.ERROR, platform.status.UnknownMethod, { method: request.method }) error: new Status(Severity.ERROR, platform.status.UnknownMethod, { method: request.method })
@ -349,7 +355,7 @@ export function serveAccount (measureCtx: MeasureContext, brandings: BrandingMap
return return
} }
return method(mctx, db, branding, request, token) return method(mctx, db, branding, request, token, meta)
}) })
const body = JSON.stringify(result) const body = JSON.stringify(result)

View File

@ -554,7 +554,7 @@ describe('account utils', () => {
param1: 'value1', param1: 'value1',
param2: 'value2' param2: 'value2'
}, },
{} undefined
) )
}) })
@ -567,7 +567,7 @@ describe('account utils', () => {
const result = await wrappedMethod(mockCtx, mockDb, mockBranding, request, 'token') const result = await wrappedMethod(mockCtx, mockDb, mockBranding, request, 'token')
expect(result).toEqual({ id: 'req1', result: mockResult }) expect(result).toEqual({ id: 'req1', result: mockResult })
expect(mockMethod).toHaveBeenCalledWith(mockCtx, mockDb, mockBranding, 'token', { param1: 'value1' }, {}) expect(mockMethod).toHaveBeenCalledWith(mockCtx, mockDb, mockBranding, 'token', { param1: 'value1' }, undefined)
}) })
test('should handle PlatformError', async () => { test('should handle PlatformError', async () => {
@ -623,9 +623,9 @@ describe('account utils', () => {
const mockMethod = jest.fn().mockResolvedValue(mockResult) const mockMethod = jest.fn().mockResolvedValue(mockResult)
const wrappedMethod = wrap(mockMethod) const wrappedMethod = wrap(mockMethod)
const mockTimezone = 'America/New_York' const mockTimezone = 'America/New_York'
const request = { id: 'req1', params: { param1: 'value1' }, headers: { 'X-Timezone': mockTimezone } } const request = { id: 'req1', params: { param1: 'value1' } }
const result = await wrappedMethod(mockCtx, mockDb, mockBranding, request, 'token') const result = await wrappedMethod(mockCtx, mockDb, mockBranding, request, 'token', { timezone: mockTimezone })
expect(result).toEqual({ id: 'req1', result: mockResult }) expect(result).toEqual({ id: 'req1', result: mockResult })
expect(mockMethod).toHaveBeenCalledWith( expect(mockMethod).toHaveBeenCalledWith(

View File

@ -119,12 +119,9 @@ export function wrap (
db: AccountDB, db: AccountDB,
branding: Branding | null, branding: Branding | null,
request: any, request: any,
token?: string token?: string,
meta?: Meta
): Promise<any> { ): Promise<any> {
const meta =
request.headers !== undefined && request.headers['X-Timezone'] !== undefined
? { timezone: request.headers['X-Timezone'] }
: {}
return await accountMethod(ctx, db, branding, token, { ...request.params }, meta) return await accountMethod(ctx, db, branding, token, { ...request.params }, meta)
.then((result) => ({ id: request.id, result })) .then((result) => ({ id: request.id, result }))
.catch((err) => { .catch((err) => {