Skip to content

Instantly share code, notes, and snippets.

@SheIITear
Last active March 16, 2024 02:42
Show Gist options
  • Save SheIITear/3357b0d2616cd030e18545c8c9b4cea7 to your computer and use it in GitHub Desktop.
Save SheIITear/3357b0d2616cd030e18545c8c9b4cea7 to your computer and use it in GitHub Desktop.
Just a piece of code you can use to handle user authentication (cookies and validating them) in memory. This is not made for anything more than testing / PoC. (ps written for a school project while getting drunk)
import { randomBytes, createHmac } from 'crypto'
interface UserData {
cookie: string
ttl: number
salt: string
}
export class Auth {
#storage: Map<string, UserData>
#secret: string
#ttl: number
constructor(secret: string, ttl: number) {
console.log(`Setting up auth storage with ttl of ${ttl}`)
this.#storage = new Map<string, UserData>()
this.#secret = secret
this.#ttl = ttl
}
private getStorage = (userId: string) => this.#storage.get(userId)
private delField = (userId: string) => this.#storage.delete(userId)
private updateStorage = (userId: string, data: UserData) => this.#storage.set(userId, data)
private userIdFromCookie = (cookie: string): string => cookie.split('.')[0]
private genCookie = (userId: string, salt: string) => {
const cookie = this.getIdentifier(userId)
const signature = this.generateSignature(cookie, salt)
return `${cookie}.${signature}`
}
private getIdentifier = (userId: string): string => {
const keyBuffer = Buffer.from(userId)
const result = keyBuffer.toString('base64')
return result
}
private generateSignature = (data: string, salt: string): string => {
const hmac = createHmac('sha256', this.#secret)
hmac.update(data + salt)
return hmac.digest('base64')
}
private verifySignature = (cookie: string, salt: string): boolean => {
const [data, signature] = cookie.split('.')
const expectedSignature = this.generateSignature(data, salt)
return signature === expectedSignature;
}
private cleaner = (userId: string) => {
setTimeout(() => {
this.delField(userId)
}, this.#ttl)
}
isUserLoggedin = (cookie: string): boolean => {
const userId = this.userIdFromCookie(cookie)
const userData = this.getStorage(userId)
if (!userData) {
return false
}
const { ttl, salt } = userData
if (ttl < Date.now()) {
this.delField(userId)
return false;
}
if (!this.verifySignature(cookie, salt)) {
return false;
}
return true;
}
setLoggedIn = (userId: string): string => {
const salt = randomBytes(16).toString('hex')
const cookie = this.genCookie(userId, salt)
const encodedId = Buffer.from(userId).toString('base64')
const userData: UserData = {
cookie: cookie,
ttl: Date.now() + this.#ttl,
salt: salt
}
this.updateStorage(encodedId, userData)
this.cleaner(encodedId)
return cookie
}
setLoggedOut = (cookie: string) => {
this.delField(this.userIdFromCookie(cookie))
return
}
}
@SheIITear
Copy link
Author

Usage:

const auth = new Auth('you will never guess this', 1*1000*60) // setup 

const cookie = auth.setLoggedIn(username) // log user in

const loggedIn = auth.isUserLoggedin(cookie) // check if cookie is valid

auth.setLoggedOut(cookie) // log out a cookie

It should be relatively easy to add stuff like user privileges etc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment