Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BLO-934 fix: 2fa time skew #1981

Merged
merged 2 commits into from
Apr 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 47 additions & 0 deletions packages/extension/src/shared/shield/backend/time.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import urlJoin from "url-join"

import { ARGENT_API_BASE_URL } from "../../api/constants"
import { fetcherWithArgentApiHeaders } from "../../api/fetcher"

interface GetTimeResponse {
time: number
}

/** backend time - at the time the response was generated - in seconds (aka 'epoch') - */

export const getBackendTimeSeconds = async () => {
try {
const fetcher = fetcherWithArgentApiHeaders()
const { time } = await fetcher<GetTimeResponse>(
urlJoin(ARGENT_API_BASE_URL, `time`),
)
return time
} catch (error) {
throw new Error("failed to request time")
}
}

/** determine skew (difference) between local time and backend time */

export const getBackendTimeSkew = async () => {
const timeStart = new Date().getTime()
const backendTimeSeconds = await getBackendTimeSeconds()
const timeNow = new Date().getTime()
/** average how long it took for one hop client -> server, or server -> client */
const responseTime = (timeNow - timeStart) / 2
/** approximate what backend time should be right now */
const backendTimeNow = backendTimeSeconds * 1000 + responseTime
/** determine skew (difference) between local time and backend time */
const backendTimeSkew = backendTimeNow - timeNow
return backendTimeSkew
}

/** determine the expected backend time right now in seconds (aka 'epoch') */

export const getBackendTimeNowSeconds = async () => {
const backendTimeSkew = await getBackendTimeSkew()
const timeNow = new Date().getTime()
const backendTimeNow = timeNow + backendTimeSkew
/** conver to epoch */
return Math.floor(backendTimeNow / 1000)
}
6 changes: 5 additions & 1 deletion packages/extension/src/shared/shield/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
generateKeyPair,
} from "jose"

import { getBackendTimeNowSeconds } from "./backend/time"
import { idb } from "./idb"

/** important that signingKey stays not 'extractable' from browser */
Expand Down Expand Up @@ -45,9 +46,12 @@ export const generateJwt = async () => {
const publicJwk = await exportJWK(publicKey)
const thumbprint = await calculateJwkThumbprint(publicJwk)

/** set issuer time from backend in case of discrepancy with local machine time */
const backendTimeNowSeconds = await getBackendTimeNowSeconds()

const jwt = await new SignJWT({})
.setProtectedHeader({ alg, jwk: publicJwk })
.setIssuedAt()
.setIssuedAt(backendTimeNowSeconds)
.setIssuer("kid:" + thumbprint)
.setExpirationTime("5m")
.sign(privateKey)
Expand Down