-
Notifications
You must be signed in to change notification settings - Fork 1
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
token retrieval without init #102
Changes from all commits
c0ef4a1
e8639d4
0a33657
bd98e5f
3af320e
b352521
2367236
e41238c
0698d87
33d978c
1fad72d
3026d31
a46d20f
4a21945
a866a10
fdfbd2b
c080e41
ee870a0
4dd3792
fd5a423
bea4d2f
3888be8
08c4c70
25b73d0
a4ea126
5e60441
c607112
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,6 +29,28 @@ function enrichIdentity(identity: LegacySDKCookie, now: number) { | |
}; | ||
} | ||
|
||
function getCookie(cookieName: string) { | ||
const docCookie = document.cookie; | ||
if (docCookie) { | ||
const payload = docCookie.split('; ').find((row) => row.startsWith(cookieName + '=')); | ||
if (payload) { | ||
return decodeURIComponent(payload.split('=')[1]); | ||
} | ||
} | ||
} | ||
|
||
export function loadIdentityFromCookieNoLegacy( | ||
cookieName: string | ||
): Identity | OptoutIdentity | null { | ||
const payload = getCookie(cookieName); | ||
if (payload) { | ||
const result = JSON.parse(payload) as unknown; | ||
if (isValidIdentity(result)) return result; | ||
if (isOptoutIdentity(result)) return result; | ||
} | ||
return null; | ||
} | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Spoke with Lionell about making this a separate function from loadIdentityFromCookie in the CookieManager since we don't want them doing any setting (including migrating and setting the legacy cookie) without init, just getting |
||
export class CookieManager { | ||
private _opts: CookieOptions; | ||
private _cookieName: string; | ||
|
@@ -62,15 +84,6 @@ export class CookieManager { | |
(previousOptions.cookieDomain ?? '') + | ||
';expires=Tue, 1 Jan 1980 23:59:59 GMT'; | ||
} | ||
private getCookie() { | ||
const docCookie = document.cookie; | ||
if (docCookie) { | ||
const payload = docCookie.split('; ').find((row) => row.startsWith(this._cookieName + '=')); | ||
if (payload) { | ||
return decodeURIComponent(payload.split('=')[1]); | ||
} | ||
} | ||
} | ||
|
||
private migrateLegacyCookie(identity: LegacySDKCookie, now: number): Identity { | ||
const newCookie = enrichIdentity(identity, now); | ||
|
@@ -79,7 +92,7 @@ export class CookieManager { | |
} | ||
|
||
public loadIdentityFromCookie(): Identity | OptoutIdentity | null { | ||
const payload = this.getCookie(); | ||
const payload = getCookie(this._cookieName); | ||
if (payload) { | ||
const result = JSON.parse(payload) as unknown; | ||
if (isValidIdentity(result)) return result; | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -90,16 +90,6 @@ testCookieAndLocalStorage(() => { | |
}); | ||
}); | ||
|
||
describe('initial state before init() is called', () => { | ||
test('should be in initialising state', () => { | ||
(expect(uid2) as any).toBeInInitialisingState(); | ||
}); | ||
|
||
test('getAdvertisingToken should return undefined', () => { | ||
expect(uid2.getAdvertisingToken()).toBeUndefined(); | ||
}); | ||
}); | ||
|
||
describe('when initialising with invalid options', () => { | ||
test('should fail on no opts', () => { | ||
expect(() => (uid2 as any).init()).toThrow(TypeError); | ||
|
@@ -1103,3 +1093,37 @@ describe('SDK bootstraps itself if init has already been completed', () => { | |
}).rejects.toThrow(); | ||
}); | ||
}); | ||
|
||
describe('Token retrieval and related public functions working without init', () => { | ||
const makeIdentity = mocks.makeIdentityV2; | ||
const email = '[email protected]'; | ||
const emailHash = 'lz3+Rj7IV4X1+Vr1ujkG7tstkxwk5pgkqJ6mXbpOgTs='; | ||
|
||
test('should be able to find identity set without init', async () => { | ||
const identity = { ...makeIdentity(), refresh_from: Date.now() + 100 }; | ||
const identityStorageFunctions = [ | ||
{ | ||
setIdentity: () => mocks.setUid2LocalStorage(identity), | ||
removeIdentity: () => mocks.removeUid2LocalStorage(), | ||
}, | ||
{ | ||
setIdentity: () => mocks.setUid2Cookie(identity), | ||
removeIdentity: () => mocks.removeUid2Cookie(), | ||
}, | ||
]; | ||
|
||
identityStorageFunctions.forEach((functions) => { | ||
functions.setIdentity(); | ||
expect(uid2.getAdvertisingToken()).toBe(identity.advertising_token); | ||
expect(uid2.getIdentity()).toStrictEqual(identity); | ||
expect(uid2.getAdvertisingTokenAsync()).resolves.toBe(identity.advertising_token); | ||
expect(async () => { | ||
await uid2.setIdentityFromEmail(email, mocks.makeCstgOption()); | ||
}).rejects.toThrow(); | ||
expect(async () => { | ||
await uid2.setIdentityFromEmailHash(emailHash, mocks.makeCstgOption()); | ||
}).rejects.toThrow(); | ||
functions.removeIdentity(); | ||
}); | ||
}); | ||
}); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ import { StorageManager } from './storageManager'; | |
import { hashAndEncodeIdentifier } from './encoding/hash'; | ||
import { ProductDetails, ProductName } from './product'; | ||
import { storeConfig, updateConfig } from './configManager'; | ||
import { loadIdentityFromCookieNoLegacy } from './cookieManager'; | ||
import { loadIdentityWithStorageKey } from './localStorageManager'; | ||
|
||
function hasExpired(expiry: number, now = Date.now()) { | ||
return expiry <= now; | ||
|
@@ -121,10 +123,12 @@ export abstract class SdkBase { | |
} | ||
|
||
public getIdentity(): Identity | null { | ||
return this._identity && !this.temporarilyUnavailable() && !isOptoutIdentity(this._identity) | ||
? this._identity | ||
const identity = this._identity ?? this.getIdentityNoInit(); | ||
return identity && !this.temporarilyUnavailable(identity) && !isOptoutIdentity(identity) | ||
? identity | ||
: null; | ||
} | ||
|
||
// When the SDK has been initialized, this function should return the token | ||
// from the most recent refresh request, if there is a request, wait for the | ||
// new token. Otherwise, returns a promise which will be resolved after init. | ||
|
@@ -260,13 +264,10 @@ export abstract class SdkBase { | |
return this._identity && !hasExpired(this._identity.refresh_expires); | ||
} | ||
|
||
private temporarilyUnavailable() { | ||
if (!this._identity && this._apiClient?.hasActiveRequests()) return true; | ||
if ( | ||
this._identity && | ||
hasExpired(this._identity.identity_expires) && | ||
!hasExpired(this._identity.refresh_expires) | ||
) | ||
private temporarilyUnavailable(identity: Identity | OptoutIdentity | null | undefined) { | ||
if (!identity && this._apiClient?.hasActiveRequests()) return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you just put a comment in here indicating that this means that the identity is expired but refreshable? Might help the next person. |
||
// returns true if identity is expired but refreshable | ||
if (identity && hasExpired(identity.identity_expires) && !hasExpired(identity.refresh_expires)) | ||
return true; | ||
return false; | ||
} | ||
|
@@ -457,6 +458,13 @@ export abstract class SdkBase { | |
); | ||
} | ||
|
||
private getIdentityNoInit() { | ||
return ( | ||
loadIdentityFromCookieNoLegacy(this._product.cookieName) ?? | ||
loadIdentityWithStorageKey(this._product.localStorageKey) | ||
); | ||
} | ||
|
||
protected async callCstgAndSetIdentity( | ||
request: { emailHash: string } | { phoneHash: string }, | ||
opts: ClientSideIdentityOptions | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This state was only used in one test, and isn't really relevant anymore since an advertising token can be found without init