Skip to content

Commit 8a42ef2

Browse files
authored
use /status to get time drift before sending any intents (#605)
1 parent 2649315 commit 8a42ef2

2 files changed

Lines changed: 79 additions & 3 deletions

File tree

packages/waas/src/auth.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,9 @@ import {
1616
SendERC721Args,
1717
SendTransactionsArgs,
1818
SignedIntent,
19-
SignMessageArgs
19+
SignMessageArgs,
20+
getTimeDrift,
21+
updateTimeDrift
2022
} from './intents'
2123
import {
2224
FeeOptionsResponse,
@@ -334,6 +336,17 @@ export class SequenceWaaS {
334336
}
335337
}
336338

339+
private async updateTimeDrift() {
340+
if (getTimeDrift() === undefined) {
341+
const res = await fetch(`${this.config.rpcServer}/status`)
342+
const date = res.headers.get('Date')
343+
if (!date) {
344+
throw new Error('failed to get Date header value from /status')
345+
}
346+
updateTimeDrift(new Date(date))
347+
}
348+
}
349+
337350
private async sendIntent(intent: SignedIntent<any>) {
338351
const sessionId = await this.waas.getSessionId()
339352
if (!sessionId) {
@@ -430,6 +443,8 @@ export class SequenceWaaS {
430443
}
431444

432445
async initAuth(identity: Identity): Promise<Challenge> {
446+
await this.updateTimeDrift()
447+
433448
if ('guest' in identity && identity.guest) {
434449
return this.initGuestAuth()
435450
} else if ('idToken' in identity) {
@@ -493,6 +508,8 @@ export class SequenceWaaS {
493508
challenge: Challenge,
494509
opts?: { sessionName?: string; forceCreateAccount?: boolean }
495510
): Promise<SignInResponse> {
511+
await this.updateTimeDrift()
512+
496513
// initAuth can start while user is already signed in and continue with linkAccount method,
497514
// but it can't be used to completeAuth while user is already signed in. In this
498515
// case we should throw an error.
@@ -559,6 +576,8 @@ export class SequenceWaaS {
559576
}
560577

561578
async dropSession({ sessionId, strict }: { sessionId?: string; strict?: boolean } = {}) {
579+
await this.updateTimeDrift()
580+
562581
const thisSessionId = await this.waas.getSessionId()
563582
if (!thisSessionId) {
564583
throw new Error('session not open')
@@ -594,6 +613,8 @@ export class SequenceWaaS {
594613
}
595614

596615
async listSessions(): Promise<Sessions> {
616+
await this.updateTimeDrift()
617+
597618
const sessionId = await this.waas.getSessionId()
598619
if (!sessionId) {
599620
throw new Error('session not open')
@@ -614,6 +635,8 @@ export class SequenceWaaS {
614635
}
615636

616637
async validateSession(args?: ValidationArgs) {
638+
await this.updateTimeDrift()
639+
617640
if (await this.isSessionValid()) {
618641
return true
619642
}
@@ -622,6 +645,8 @@ export class SequenceWaaS {
622645
}
623646

624647
async finishValidateSession(challenge: string): Promise<boolean> {
648+
await this.updateTimeDrift()
649+
625650
const intent = await this.waas.finishValidateSession(this.validationRequiredSalt, challenge)
626651
const result = await this.sendIntent(intent)
627652

@@ -634,6 +659,8 @@ export class SequenceWaaS {
634659
}
635660

636661
async isSessionValid(): Promise<boolean> {
662+
await this.updateTimeDrift()
663+
637664
const intent = await this.waas.getSession()
638665
const result = await this.sendIntent(intent)
639666

@@ -659,11 +686,15 @@ export class SequenceWaaS {
659686
}
660687

661688
async sessionAuthProof({ nonce, network, validation }: { nonce?: string; network?: string; validation?: ValidationArgs }) {
689+
await this.updateTimeDrift()
690+
662691
const intent = await this.waas.sessionAuthProof({ nonce, network })
663692
return await this.trySendIntent({ validation }, intent, isSessionAuthProofResponse)
664693
}
665694

666695
async listAccounts() {
696+
await this.updateTimeDrift()
697+
667698
const intent = await this.waas.listAccounts()
668699
const res = await this.sendIntent(intent)
669700

@@ -675,6 +706,8 @@ export class SequenceWaaS {
675706
}
676707

677708
async linkAccount(challenge: Challenge) {
709+
await this.updateTimeDrift()
710+
678711
const intent = await this.waas.linkAccount(challenge.getIntentParams())
679712
const res = await this.sendIntent(intent)
680713

@@ -686,11 +719,15 @@ export class SequenceWaaS {
686719
}
687720

688721
async removeAccount(accountId: string) {
722+
await this.updateTimeDrift()
723+
689724
const intent = await this.waas.removeAccount({ accountId })
690725
await this.sendIntent(intent)
691726
}
692727

693728
async getIdToken(args?: { nonce?: string }): Promise<IntentResponseIdToken> {
729+
await this.updateTimeDrift()
730+
694731
const intent = await this.waas.getIdToken({ nonce: args?.nonce })
695732
const res = await this.sendIntent(intent)
696733

@@ -737,6 +774,8 @@ export class SequenceWaaS {
737774
}
738775

739776
async signMessage(args: WithSimpleNetwork<SignMessageArgs> & CommonAuthArgs): Promise<SignedMessageResponse> {
777+
await this.updateTimeDrift()
778+
740779
const intent = await this.waas.signMessage(await this.useIdentifier(args))
741780
return this.trySendIntent(args, intent, isSignedMessageResponse)
742781
}
@@ -764,31 +803,43 @@ export class SequenceWaaS {
764803
}
765804

766805
async sendTransaction(args: WithSimpleNetwork<SendTransactionsArgs> & CommonAuthArgs): Promise<MaySentTransactionResponse> {
806+
await this.updateTimeDrift()
807+
767808
const intent = await this.waas.sendTransaction(await this.useIdentifier(args))
768809
return this.trySendTransactionIntent(intent, args)
769810
}
770811

771812
async sendERC20(args: WithSimpleNetwork<SendERC20Args> & CommonAuthArgs): Promise<MaySentTransactionResponse> {
813+
await this.updateTimeDrift()
814+
772815
const intent = await this.waas.sendERC20(await this.useIdentifier(args))
773816
return this.trySendTransactionIntent(intent, args)
774817
}
775818

776819
async sendERC721(args: WithSimpleNetwork<SendERC721Args> & CommonAuthArgs): Promise<MaySentTransactionResponse> {
820+
await this.updateTimeDrift()
821+
777822
const intent = await this.waas.sendERC721(await this.useIdentifier(args))
778823
return this.trySendTransactionIntent(intent, args)
779824
}
780825

781826
async sendERC1155(args: WithSimpleNetwork<SendERC1155Args> & CommonAuthArgs): Promise<MaySentTransactionResponse> {
827+
await this.updateTimeDrift()
828+
782829
const intent = await this.waas.sendERC1155(await this.useIdentifier(args))
783830
return this.trySendTransactionIntent(intent, args)
784831
}
785832

786833
async callContract(args: WithSimpleNetwork<SendContractCallArgs> & CommonAuthArgs): Promise<MaySentTransactionResponse> {
834+
await this.updateTimeDrift()
835+
787836
const intent = await this.waas.callContract(await this.useIdentifier(args))
788837
return this.trySendTransactionIntent(intent, args)
789838
}
790839

791840
async feeOptions(args: WithSimpleNetwork<SendTransactionsArgs> & CommonAuthArgs): Promise<FeeOptionsResponse> {
841+
await this.updateTimeDrift()
842+
792843
const intent = await this.waas.feeOptions(await this.useIdentifier(args))
793844
return this.trySendIntent(args, intent, isFeeOptionsResponse)
794845
}

packages/waas/src/intents/base.ts

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,34 @@ export type SignedIntent<T> = Omit<RawIntent, 'data'> & { data: T }
1111
const INTENTS_VERSION = 1
1212
const VERSION = `${INTENTS_VERSION} (Web ${PACKAGE_VERSION})`
1313

14+
let timeDrift: number | undefined
15+
const timeDriftKey = '@sequence.timeDrift'
16+
17+
function isSessionStorageAvailable() {
18+
return typeof window === 'object' && typeof window.sessionStorage === 'object'
19+
}
20+
21+
export function getTimeDrift() {
22+
if (isSessionStorageAvailable()) {
23+
const drift = window.sessionStorage.getItem(timeDriftKey)
24+
if (drift) {
25+
return parseInt(drift, 10)
26+
}
27+
}
28+
return timeDrift
29+
}
30+
31+
export function updateTimeDrift(serverTime: Date) {
32+
timeDrift = (Date.now() - serverTime.getTime()) / 1000
33+
if (isSessionStorageAvailable()) {
34+
window.sessionStorage.setItem(timeDriftKey, timeDrift.toString(10))
35+
}
36+
}
37+
1438
export function makeIntent<T>(name: IntentName, lifespan: number, data: T): Intent<T> {
15-
const issuedAt = Math.floor(Date.now() / 1000)
16-
const expiresAt = issuedAt + lifespan
39+
const drift = Math.abs(Math.floor(getTimeDrift() || 0))
40+
const issuedAt = Math.floor(Date.now() / 1000 - drift)
41+
const expiresAt = issuedAt + lifespan + 2*drift
1742
return {
1843
version: VERSION,
1944
issuedAt,

0 commit comments

Comments
 (0)