@@ -38,20 +38,29 @@ const TEMP_AUTH_CODE_TTL = 5 * 60_000
3838/** Failed attempts allowed against a single code before it is rotated. */
3939const TEMP_AUTH_MAX_ATTEMPTS = 5
4040
41- let tempAuthCode : string = generateTempCode ( )
42- let tempAuthCodeExpiresAt : number = Date . now ( ) + TEMP_AUTH_CODE_TTL
41+ let tempAuthCode : string | undefined
42+ let tempAuthCodeExpiresAt = 0
4343let tempAuthFailedAttempts = 0
4444
4545function generateTempCode ( ) : string {
4646 return randomDigits ( TEMP_AUTH_CODE_LENGTH )
4747}
4848
49+ function ensureTempAuthCode ( ) : string {
50+ if ( tempAuthCode === undefined ) {
51+ tempAuthCode = generateTempCode ( )
52+ tempAuthCodeExpiresAt = Date . now ( ) + TEMP_AUTH_CODE_TTL
53+ }
54+
55+ return tempAuthCode
56+ }
57+
4958/**
5059 * The current one-time authentication code. Display this to the user (e.g. in
5160 * the dev-server terminal) so they can type it into the browser to authenticate.
5261 */
5362export function getTempAuthCode ( ) : string {
54- return tempAuthCode
63+ return ensureTempAuthCode ( )
5564}
5665
5766/**
@@ -78,7 +87,7 @@ export function refreshTempAuthCode(): string {
7887 * `Referer` header; the browser client reads it locally (see
7988 * `consumeOtpFromUrl`). Any existing fragment parameters are preserved.
8089 */
81- export function buildOtpAuthUrl ( baseUrl : string , code : string = tempAuthCode ) : string {
90+ export function buildOtpAuthUrl ( baseUrl : string , code : string = getTempAuthCode ( ) ) : string {
8291 const url = new URL ( baseUrl )
8392 const fragment = new URLSearchParams ( url . hash . replace ( / ^ # / , '' ) )
8493 fragment . set ( DEVFRAME_OTP_URL_PARAM , code )
@@ -125,13 +134,15 @@ export function exchangeTempAuthCode(
125134 info : { ua : string , origin : string } ,
126135 storage : SharedState < InternalAnonymousAuthStorage > ,
127136) : string | null {
137+ const currentTempAuthCode = ensureTempAuthCode ( )
138+
128139 // Expired code: rotate so a stale code can never be redeemed.
129140 if ( Date . now ( ) > tempAuthCodeExpiresAt ) {
130141 refreshTempAuthCode ( )
131142 return null
132143 }
133144
134- if ( ! timingSafeEqual ( code , tempAuthCode ) ) {
145+ if ( ! timingSafeEqual ( code , currentTempAuthCode ) ) {
135146 tempAuthFailedAttempts += 1
136147 // Too many wrong guesses, so invalidate this code entirely.
137148 if ( tempAuthFailedAttempts >= TEMP_AUTH_MAX_ATTEMPTS )
0 commit comments