Skip to content

Commit

Permalink
feat: Adds sanitizeJWTBearerAuthFromString (#478)
Browse files Browse the repository at this point in the history
  • Loading branch information
ryasmi authored Sep 21, 2021
1 parent 2b40a70 commit 4ecaa02
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
1 change: 1 addition & 0 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ Finally, Rulr is starting to provide rules that sanitize inputs.
- [sanitizeJsonFromString](./src/sanitizationRules/sanitizeJsonFromString/readme.md)
- [sanitizeNumberFromString](./src/sanitizationRules/sanitizeNumberFromString/readme.md)
- [sanitizeBasicAuthFromString](./src/sanitizationRules/sanitizeBasicAuthFromString/readme.md)
- [sanitizeJWTBearerAuthFromString](./src/sanitizationRules/sanitizeJWTBearerAuthFromString/readme.md)

### Frequently Awesome Questions 🤘

Expand Down
55 changes: 55 additions & 0 deletions src/sanitizationRules/sanitizeJWTBearerAuthFromString/readme.md
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',
})
```
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)
})
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()
}

0 comments on commit 4ecaa02

Please sign in to comment.