-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Adds
sanitizeJWTBearerAuthFromString
(#478)
- Loading branch information
Showing
4 changed files
with
149 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
55 changes: 55 additions & 0 deletions
55
src/sanitizationRules/sanitizeJWTBearerAuthFromString/readme.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
# sanitizeJWTBearerAuthFromString | ||
|
||
[Back to root readme.md](../../../readme.md) | ||
|
||
This function uses `rulr.isJWTBearerAuthAsString` and can be used when you want to sanitize an input to be a JWT bearer auth from a string as shown in the example below. This function should only throw `rulr.InvalidJWTBearerAuthAsString`. | ||
|
||
```ts | ||
import * as rulr from 'rulr' | ||
|
||
const constrainToExample = rulr.object({ | ||
required: { | ||
example: rulr.sanitizeJWTBearerAuthFromString, | ||
}, | ||
}) | ||
|
||
type Example = rulr.Static<typeof constrainToExample> | ||
// { | ||
// example: rulr.JWTBearerAuth | ||
// } | ||
|
||
// Valid - Returns { token: 'a.b.c' } as instance of rulr.JWTBearerAuth | ||
const example1: Example = constrainToExample({ | ||
example: 'Bearer a.b.c', | ||
}) | ||
|
||
// Invalid: Not a string | ||
const example2: Example = constrainToExample({ | ||
example: 10, | ||
}) | ||
|
||
// Invalid: Not a valid JWT token, contains invalid & character | ||
const example3: Example = constrainToExample({ | ||
example: 'Bearer &.&.&', | ||
}) | ||
|
||
// Invalid: Not a valid prefix | ||
const example4: Example = constrainToExample({ | ||
example: ' Bearera.b.c', // ' BearerYWJjOmRlZg==' | ||
}) | ||
|
||
// Invalid: Missing JWT token | ||
const example5: Example = constrainToExample({ | ||
example: 'Bearer ', | ||
}) | ||
|
||
// Invalid: Too few dot separators | ||
const example6: Example = constrainToExample({ | ||
example: 'Bearer a.bc', | ||
}) | ||
|
||
// Invalid: Too many dot separators | ||
const example7: Example = constrainToExample({ | ||
example: 'Bearer a.b.c.d', | ||
}) | ||
``` |
60 changes: 60 additions & 0 deletions
60
...sanitizationRules/sanitizeJWTBearerAuthFromString/sanitizeJWTBearerAuthFromString.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import * as assert from 'assert' | ||
import btoa from 'btoa' | ||
import { | ||
sanitizeJWTBearerAuthFromString, | ||
JWTBearerAuthAsString, | ||
InvalidJWTBearerAuthAsString, | ||
isJWTBearerAuthAsString, | ||
JWTBearerAuth, | ||
} from './sanitizeJWTBearerAuthFromString' | ||
|
||
test('sanitizeJWTBearerAuthFromString should return key and secret for valid tokens', () => { | ||
// Example from https://jwt.io/ | ||
const bearerAuthToken = | ||
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c' | ||
const input = `Bearer ${bearerAuthToken}` | ||
const output: JWTBearerAuth = sanitizeJWTBearerAuthFromString(input) | ||
assert.ok(output instanceof JWTBearerAuth) | ||
assert.strictEqual(output.token, bearerAuthToken) | ||
assert.ok(isJWTBearerAuthAsString(input)) | ||
const typeOutput: JWTBearerAuthAsString = input | ||
assert.strictEqual(typeOutput, input) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that is not a string', () => { | ||
const input = 10 | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that uses invalid JWT token', () => { | ||
const input = 'Bearer &.&.&' | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that is missing a JWT token', () => { | ||
const input = 'Bearer ' | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that has too few dot separators', () => { | ||
const input = `Basic a.bc` | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that has too many dot separators', () => { | ||
const token = btoa('a.b.c.d') | ||
const input = `Basic ${token}` | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) | ||
|
||
test('sanitizeJWTBearerAuthFromString should now allow value that uses incorrect prefix', () => { | ||
const token = 'a.b.c' | ||
const input = ` Bearer${token}` | ||
assert.throws(() => sanitizeJWTBearerAuthFromString(input), InvalidJWTBearerAuthAsString) | ||
assert.strictEqual(isJWTBearerAuthAsString(input), false) | ||
}) |
33 changes: 33 additions & 0 deletions
33
src/sanitizationRules/sanitizeJWTBearerAuthFromString/sanitizeJWTBearerAuthFromString.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import { BaseError } from 'make-error' | ||
import { isString } from '../../valueRules/string/string' | ||
import { Constrained } from '../../core' | ||
|
||
export class InvalidJWTBearerAuthAsString extends BaseError { | ||
constructor() { | ||
super('expected JWT bearer auth from string') | ||
} | ||
} | ||
|
||
export const jwtBearerAuthAsStringSymbol = Symbol() | ||
|
||
export type JWTBearerAuthAsString = Constrained<typeof jwtBearerAuthAsStringSymbol, string> | ||
|
||
const encodedRegex = /^Bearer ([A-Za-z0-9-_]*\.[A-Za-z0-9-_]*\.[A-Za-z0-9-_]*)$/ | ||
|
||
export function isJWTBearerAuthAsString(input: unknown): input is JWTBearerAuthAsString { | ||
return isString(input) && encodedRegex.test(input) | ||
} | ||
|
||
export class JWTBearerAuth { | ||
constructor(public readonly token: string) {} | ||
} | ||
|
||
export function sanitizeJWTBearerAuthFromString(input: unknown): JWTBearerAuth { | ||
if (isString(input)) { | ||
const matches = encodedRegex.exec(input) | ||
if (matches !== null) { | ||
return new JWTBearerAuth(matches[1]) | ||
} | ||
} | ||
throw new InvalidJWTBearerAuthAsString() | ||
} |