Skip to content

Commit 0e38b6d

Browse files
authored
Merge pull request #89 from wadetandy/master
Always delegate JWT to storage backend
2 parents 54029f6 + 41b62dd commit 0e38b6d

File tree

8 files changed

+298
-204
lines changed

8 files changed

+298
-204
lines changed

src/credential-storage.ts

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,21 @@ export interface StorageBackend {
44
removeItem(key: string): void
55
}
66

7-
export class NullStorageBackend implements StorageBackend {
8-
getItem(key: string) {
9-
return null
7+
export class InMemoryStorageBackend implements StorageBackend {
8+
private _data : Record<string, string | undefined>
9+
10+
constructor() {
11+
this._data = {}
12+
}
13+
14+
getItem(key: string) : string | null {
15+
return this._data[key] || null // Cast undefined to null
1016
}
1117
setItem(key: string, value: string | undefined) {
12-
/*noop*/
18+
this._data[key] = value
1319
}
1420
removeItem(key: string) {
15-
/*noop*/
21+
delete this._data[key]
1622
}
1723
}
1824

@@ -22,36 +28,34 @@ let defaultBackend: StorageBackend
2228
try {
2329
defaultBackend = localStorage
2430
} catch (e) {
25-
defaultBackend = new NullStorageBackend()
31+
defaultBackend = new InMemoryStorageBackend()
2632
}
2733

2834
export class CredentialStorage {
29-
private _jwtKey: string | false
35+
private _jwtKey: string
3036
private _backend: StorageBackend
3137

3238
constructor(
33-
jwtKey: string | false,
39+
jwtKey: string,
3440
backend: StorageBackend = defaultBackend
3541
) {
3642
this._jwtKey = jwtKey
3743
this._backend = backend
3844
}
3945

40-
getJWT(): string | null {
41-
if (this._jwtKey) {
42-
return this._backend.getItem(this._jwtKey)
43-
} else {
44-
return null
45-
}
46+
get backend() : StorageBackend {
47+
return this._backend
48+
}
49+
50+
getJWT(): string | undefined {
51+
return this._backend.getItem(this._jwtKey) || undefined
4652
}
4753

4854
setJWT(value: string | undefined | null): void {
49-
if (this._jwtKey) {
50-
if (value) {
51-
this._backend.setItem(this._jwtKey, value)
52-
} else {
53-
this._backend.removeItem(this._jwtKey)
54-
}
55+
if (value) {
56+
this._backend.setItem(this._jwtKey, value)
57+
} else {
58+
this._backend.removeItem(this._jwtKey)
5559
}
5660
}
5761
}

src/model.ts

Lines changed: 57 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { WritePayload } from "./util/write-payload"
88
import { flipEnumerable, getNonEnumerables } from "./util/enumerables"
99
import {
1010
CredentialStorage,
11-
NullStorageBackend,
11+
InMemoryStorageBackend,
1212
StorageBackend
1313
} from "./credential-storage"
1414
import { IDMap } from "./id-map"
@@ -53,6 +53,7 @@ export interface ModelConfiguration {
5353
apiNamespace: string
5454
jsonapiType: string
5555
endpoint: string
56+
credentialStorageBackend: StorageBackend,
5657
jwt: string
5758
jwtStorage: string | false
5859
keyCase: KeyCase
@@ -117,6 +118,26 @@ export const applyModelConfig = <T extends typeof JSORMBase>(
117118
): void => {
118119
let k: keyof ModelConfigurationOptions
119120

121+
config = { ...config } // clone since we're going to mutate it
122+
123+
// Handle all JWT configuration at once since it's run-order dependent
124+
// We'll delete each key we encounter then pass the rest off to
125+
// a loop for assigning other arbitrary options
126+
if (config.credentialStorageBackend) {
127+
ModelClass.credentialStorageBackend = config.credentialStorageBackend
128+
delete config.jwtStorage
129+
}
130+
131+
if (config.jwtStorage) {
132+
ModelClass.jwtStorage = config.jwtStorage
133+
delete config.jwtStorage
134+
}
135+
136+
if (config.jwt) {
137+
ModelClass.setJWT(config.jwt)
138+
delete config.jwt
139+
}
140+
120141
for (k in config) {
121142
if (config.hasOwnProperty(k)) {
122143
ModelClass[k] = config[k]
@@ -136,7 +157,6 @@ export class JSORMBase {
136157
static jsonapiType?: string
137158
static endpoint: string
138159
static isBaseClass: boolean
139-
static jwt?: string
140160
static keyCase: KeyCase = { server: "snake", client: "camel" }
141161
static strictAttributes: boolean = false
142162
static logger: ILogger = defaultLogger
@@ -148,36 +168,48 @@ export class JSORMBase {
148168
static currentClass: typeof JSORMBase = JSORMBase
149169
static beforeFetch: BeforeFilter | undefined
150170
static afterFetch: AfterFilter | undefined
151-
static jwtStorage: string | false = "jwt"
152171

153172
private static _typeRegistry: JsonapiTypeRegistry
154173
private static _IDMap: IDMap
155174
private static _middlewareStack: MiddlewareStack
156-
private static _credentialStorageBackend?: StorageBackend
157-
private static _credentialStorage?: CredentialStorage
175+
private static _credentialStorageBackend: StorageBackend
176+
private static _credentialStorage: CredentialStorage
177+
private static _jwtStorage: string | false = "jwt"
158178

159179
static get credentialStorage(): CredentialStorage {
160-
if (!this._credentialStorage) {
161-
if (!this._credentialStorageBackend) {
162-
if (this.jwtStorage && typeof localStorage !== "undefined") {
163-
this._credentialStorageBackend = localStorage
164-
} else {
165-
this._credentialStorageBackend = new NullStorageBackend()
166-
}
167-
}
180+
return this._credentialStorage
181+
}
168182

169-
this._credentialStorage = new CredentialStorage(
170-
this.jwtStorage,
171-
this._credentialStorageBackend
172-
)
183+
static set jwtStorage(val : string | false) {
184+
if (val !== this._jwtStorage) {
185+
this._jwtStorage = val
186+
this.credentialStorageBackend = this._credentialStorageBackend
173187
}
188+
}
174189

175-
return this._credentialStorage
190+
static get jwtStorage() : string | false {
191+
return this._jwtStorage
176192
}
177193

178-
static set credentialStorageBackend(backend: StorageBackend | undefined) {
194+
static set credentialStorageBackend(backend: StorageBackend) {
179195
this._credentialStorageBackend = backend
180-
this._credentialStorage = undefined
196+
197+
this._credentialStorage = new CredentialStorage(
198+
this.jwtStorage || 'jwt',
199+
this._credentialStorageBackend
200+
)
201+
}
202+
203+
static get credentialStorageBackend() : StorageBackend {
204+
return this._credentialStorageBackend
205+
}
206+
207+
static initializeCredentialStorage() {
208+
if (this.jwtStorage && typeof localStorage !== "undefined") {
209+
this.credentialStorageBackend = localStorage
210+
} else {
211+
this.credentialStorageBackend = new InMemoryStorageBackend()
212+
}
181213
}
182214

183215
/*
@@ -228,9 +260,6 @@ export class JSORMBase {
228260
if (!this._IDMap) {
229261
this._IDMap = new IDMap()
230262
}
231-
232-
const jwt = this.credentialStorage.getJWT()
233-
this.setJWT(jwt)
234263
}
235264

236265
static isSubclassOf(maybeSuper: typeof JSORMBase): boolean {
@@ -753,22 +782,16 @@ export class JSORMBase {
753782
}
754783

755784
static setJWT(token: string | undefined | null): void {
756-
if (this.baseClass === undefined) {
757-
throw new Error(`Cannot set JWT on ${this.name}: No base class present.`)
758-
}
759-
760-
this.baseClass.jwt = token || undefined
761785
this.credentialStorage.setJWT(token)
762786
}
763787

764788
static getJWT(): string | undefined {
765-
const owner = this.baseClass
766-
767-
if (owner) {
768-
return owner.jwt
769-
}
789+
return this.credentialStorage.getJWT()
770790
}
771791

792+
static get jwt(): string | undefined { return this.getJWT() }
793+
static set jwt(token: string | undefined) { this.setJWT(token) }
794+
772795
static generateAuthHeader(jwt: string): string {
773796
return `Token token="${jwt}"`
774797
}
@@ -897,6 +920,7 @@ export class JSORMBase {
897920
}
898921

899922
;(<any>JSORMBase.prototype).klass = JSORMBase
923+
JSORMBase.initializeCredentialStorage()
900924

901925
export const isModelClass = (arg: any): arg is typeof JSORMBase => {
902926
if (!arg) {

0 commit comments

Comments
 (0)