Skip to content

Commit

Permalink
feat: basic jwt support
Browse files Browse the repository at this point in the history
  • Loading branch information
tchardin committed Oct 11, 2023
1 parent f2fbf90 commit 1bdd38f
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 1 deletion.
18 changes: 17 additions & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ import { CID } from 'multiformats'
import { extractVerifiedContent } from './utils/car.js'
import { asAsyncIterable, asyncIteratorToBuffer } from './utils/itr.js'
import { randomUUID } from './utils/uuid.js'
import { getJWT } from './utils/jwt.js'

class Saturn {
/**
*
* @param {object} [opts={}]
* @param {string} [opts.clientKey]
* @param {string} [opts.clientId=randomUUID()]
* @param {string} [opts.cdnURL=saturn.ms]
* @param {number} [opts.connectTimeout=5000]
Expand All @@ -18,13 +20,15 @@ class Saturn {
clientId: randomUUID(),
cdnURL: 'saturn.ms',
logURL: 'https://twb3qukm2i654i3tnvx36char40aymqq.lambda-url.us-west-2.on.aws/',
authURL: 'https://fz3dyeyxmebszwhuiky7vggmsu0rlkoy.lambda-url.us-west-2.on.aws/',
connectTimeout: 5_000,
downloadTimeout: 0
}, opts)

this.logs = []
this.reportingLogs = process?.env?.NODE_ENV !== 'development'
this.hasPerformanceAPI = typeof window !== 'undefined' && window?.performance
this.isBrowser = typeof window !== 'undefined'
if (this.reportingLogs && this.hasPerformanceAPI) {
this._monitorPerformanceBuffer()
}
Expand All @@ -43,7 +47,9 @@ class Saturn {
const [cid] = (cidPath ?? '').split('/')
CID.parse(cid)

const options = Object.assign({}, this.opts, { format: 'car' }, opts)
const jwt = await getJWT(this.opts)

const options = Object.assign({}, this.opts, { format: 'car', jwt }, opts)
const url = this.createRequestURL(cidPath, options)

const log = {
Expand All @@ -56,6 +62,12 @@ class Saturn {
controller.abort()
}, options.connectTimeout)

if (!this.isBrowser) {
options.headers = {
Authorization: 'Bearer ' + options.jwt
}
}

let res
try {
res = await fetch(url, { signal: controller.signal, ...options })
Expand Down Expand Up @@ -155,6 +167,10 @@ class Saturn {
url.searchParams.set('dag-scope', 'entity')
}

if (this.isBrowser) {
url.searchParams.set('jwt', opts.jwt)
}

return url
}

Expand Down
43 changes: 43 additions & 0 deletions src/utils/jwt.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { base64 } from 'multiformats/bases/base64'
import { bytes } from 'multiformats'

const JWT_KEY = 'strn/jwt'

const memoryStorage = {}

function getFromStorage () {
try {
return window.localStorage.getItem(JWT_KEY)
} catch (e) {
return memoryStorage[JWT_KEY]
}
}

function setInStorage (jwt) {
try {
window.localStorage.setItem(JWT_KEY, jwt)
} catch (e) {
memoryStorage[JWT_KEY] = jwt
}
}

export function isJwtValid (jwt) {
if (!jwt) return false
const { exp } = JSON.parse(bytes.toString(base64.decode('m' + jwt.split('.')[1])))
return Date.now() < exp * 1000
}

export async function getJWT (opts) {
const jwt = getFromStorage()
if (isJwtValid(jwt)) return jwt

const { clientKey, authURL } = opts
const url = `${authURL}?clientKey=${clientKey}`

const result = await fetch(url)
const { token } = await result.json()

setInStorage(token)

return token
}
10 changes: 10 additions & 0 deletions test/jwt.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { isJwtValid } from '#src/utils/jwt.js'
import { describe, it } from 'node:test'
import assert from 'node:assert/strict'

describe('JWT tests', () => {
it('should validate a jwt', () => {
const fixture = 'eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJqdGkiOiI2NGQ1ZGI0ZC1jYmQ3LTRkYWMtOWY4Zi01NGQyMjk0OGE3Y2UiLCJzdWIiOiJhYmMxMjMiLCJzdWJUeXBlIjoiY2xpZW50S2V5IiwiYWxsb3dfbGlzdCI6WyIqIl0sImlhdCI6MTY5NjQ3MTQ5MSwiZXhwIjoxNjk2NDc1MDkxfQ.ZJeuzb6JucwUarI7_MlomTjow4Lc4RHZsPhqDepT1q6Pxs5KNVeOQwdZeCDqFSa8QQTiK-VHoKtDH7x349F5QA'
assert.equal(isJwtValid(fixture), false)
})
})

0 comments on commit 1bdd38f

Please sign in to comment.