mirror of
https://git.stupid.fish/teidesu/scripts.git
synced 2025-07-28 02:32:11 +10:00
chore: update public repo
This commit is contained in:
parent
e0109980c0
commit
e7c9507247
25 changed files with 5364 additions and 0 deletions
78
utils/oauth.ts
Normal file
78
utils/oauth.ts
Normal file
|
@ -0,0 +1,78 @@
|
|||
import type { MaybePromise } from '@fuman/utils'
|
||||
import * as fsp from 'node:fs/promises'
|
||||
import { z } from 'zod'
|
||||
|
||||
export interface OauthStorage {
|
||||
write: (value: string) => MaybePromise<void>
|
||||
read: () => MaybePromise<string | null>
|
||||
}
|
||||
|
||||
export class LocalOauthStorage implements OauthStorage {
|
||||
constructor(private filename: string) {}
|
||||
|
||||
async write(value: string) {
|
||||
await fsp.writeFile(this.filename, value)
|
||||
}
|
||||
|
||||
async read() {
|
||||
try {
|
||||
return await fsp.readFile(this.filename, 'utf8')
|
||||
} catch (e) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const OauthState = z.object({
|
||||
accessToken: z.string(),
|
||||
refreshToken: z.string().optional(),
|
||||
expiresAt: z.number(),
|
||||
})
|
||||
type OauthState = z.infer<typeof OauthState>
|
||||
|
||||
export class OauthHandler {
|
||||
constructor(private params: {
|
||||
storage: OauthStorage
|
||||
refreshToken: (refreshToken: string) => MaybePromise<{
|
||||
accessToken: string
|
||||
refreshToken: string
|
||||
expiresIn: number
|
||||
}>
|
||||
/** number of milliseconds to subtract from token expiration time */
|
||||
jitter?: number
|
||||
}) {
|
||||
this.params.jitter = this.params.jitter ?? 5000
|
||||
}
|
||||
|
||||
#cache: OauthState | null = null
|
||||
async readOauthState() {
|
||||
if (this.#cache) return this.#cache
|
||||
const value = await this.params.storage.read()
|
||||
if (!value) return null
|
||||
|
||||
return OauthState.parse(JSON.parse(value))
|
||||
}
|
||||
|
||||
async writeOauthState(value: OauthState) {
|
||||
this.#cache = value
|
||||
await this.params.storage.write(JSON.stringify(value))
|
||||
}
|
||||
|
||||
async getAccessToken() {
|
||||
const state = await this.readOauthState()
|
||||
if (!state) return null
|
||||
|
||||
if (state.expiresAt < Date.now() + this.params.jitter!) {
|
||||
if (!state.refreshToken) return null
|
||||
const { accessToken, refreshToken, expiresIn } = await this.params.refreshToken(state.refreshToken)
|
||||
await this.writeOauthState({
|
||||
accessToken,
|
||||
refreshToken,
|
||||
expiresAt: Date.now() + expiresIn * 1000,
|
||||
})
|
||||
return accessToken
|
||||
}
|
||||
|
||||
return state.accessToken
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue