import { Params } from "express-serve-static-core" ; import { getParam } from "@fluidframework/server-services-utils" ; import { ITokenClaims } from "@fluidframework/protocol-definitions" ; import { NetworkError } from "@fluidframework/server-services-client" ; import { Lumberjack } from "@fluidframework/server-services-telemetry" ; import * as jwt from "jsonwebtoken" ; import winston from "winston" ; import safeStringify from "json-stringify-safe" ; export function normalizePort ( val ) { const normalizedPort = parseInt ( val , 10 ) ; if ( isNaN ( normalizedPort ) ) { return val ; } if ( normalizedPort >= 0 ) { return normalizedPort ; } return false ; } export function getTokenLifetimeInSec ( token ) { const claims = jwt . decode ( token ) as ITokenClaims ; if ( claims && claims . exp ) { return ( claims . exp - Math . round ( ( new Date ( ) . getTime ( ) ) / 1000 ) ) ; } return undefined ; } export function getTenantIdFromRequest ( params ) { const tenantId = getParam ( params , "tenantId" ) ; if ( tenantId !== undefined ) { return tenantId ; } const id = getParam ( params , "id" ) ; if ( id !== undefined ) { return id ; } return "-" ; } export function getDocumentIdFromRequest ( tenantId , authorization ) { try { const token = parseToken ( tenantId , authorization ) ; const decoded = jwt . decode ( token ) as ITokenClaims ; return decoded . documentId ; } catch ( err ) { return "-" ; } } export function parseToken ( tenantId , authorization ) { let token ; if ( authorization ) { const base64TokenMatch = authorization . match ( /Basic (.+)/ ) ; if ( ! base64TokenMatch ) { throw new NetworkError ( 403 , "Malformed authorization token" ) ; } const encoded = Buffer . from ( base64TokenMatch [ 1 ] , "base64" ) . toString ( ) ; const tokenMatch = encoded . match ( /(.+):(.+)/ ) ; if ( ! tokenMatch || tenantId !== tokenMatch [ 1 ] ) { throw new NetworkError ( 403 , "Malformed authorization token" ) ; } token = tokenMatch [ 2 ] ; } return token ; } param url param method param lumberProperties export function getRequestErrorTranslator ( url , method , lumberProperties ? ) { const standardLogErrorMessage = `[${ method }] Request to [${ url }] failed` ; const requestErrorTranslator = ( error ) : never => { if ( typeof error === "object" && error instanceof Error && error . name === "NetworkError" ) { const networkError = error as NetworkError ; winston . error ( `${ standardLogErrorMessage }: [statusCode: ${ networkError . code }], [details: ${ safeStringify ( networkError . details ) ?? "undefined" }]` ) ; Lumberjack . error ( `${ standardLogErrorMessage }: [statusCode: ${ networkError . code }], [details: ${ safeStringify ( networkError . details ) ?? "undefined" }]` , lumberProperties ) ; throw error ; } else if ( typeof error === "number" || ! Number . isNaN ( Number . parseInt ( error , 10 ) ) ) { const errorCode = typeof error === "number" ? error : Number . parseInt ( error , 10 ) ; winston . error ( `${ standardLogErrorMessage }: [statusCode: ${ errorCode }]` ) ; Lumberjack . error ( `${ standardLogErrorMessage }: [statusCode: ${ errorCode }]` , lumberProperties ) ; throw new NetworkError ( errorCode , "Internal Service Request Failed" ) ; } winston . error ( `${ standardLogErrorMessage }: ${ safeStringify ( error ) }` ) ; Lumberjack . error ( standardLogErrorMessage , lumberProperties , error ) ; throw new NetworkError ( 500 , "Internal Server Error" ) ; } ; return requestErrorTranslator ; }