import * as cookie from 'https://deno.land/std@0.188.0/http/cookie.ts' export class Auth { constructor({ baseUrl, remoteBaseUrl, giteaApiBaseUrl, giteaWebBaseUrl, giteaClientId, giteaClientSecret }) { this.baseUrl = baseUrl this.remoteBaseUrl = remoteBaseUrl this.giteaApiBaseUrl = giteaApiBaseUrl this.giteaWebBaseUrl = giteaWebBaseUrl this.giteaClientId = giteaClientId this.giteaClientSecret = giteaClientSecret } redirectUrl(state) { const url = new URL( this.giteaWebBaseUrl + '/login/oauth/authorize' ) const search = new URLSearchParams() search.set('response_type', 'code') search.set('client_id', this.giteaClientId) search.set( 'redirect_uri', this.remoteBaseUrl + '/api/auth/callback' ) search.set('state', state) url.search = search.toString() return url.toString() } buildState() { const timestamp = new Date().valueOf() const randomInt = Math.floor(Math.random() * 10000) // TODO: sign return `${randomInt}-${timestamp}` } async redirect(event) { const state = this.buildState() const url = this.redirectUrl(state) const headers = new Headers({ Location: url }) cookie.setCookie(headers, { name: 'oauth.gitea.state', value: state, }) event.respondWith(new Response('', { headers, status: 302, })) } getToken(code) { this._code = code return 'test' } async callback(event) { const url = new URL(event.request.url) const { state, code } = Object.fromEntries( url.searchParams.entries() ) const cookies = cookie.getCookies( event.request.headers ) const headers = new Headers({ Location: '/#/' }) if (cookies['oauth.gitea.state'] !== state) { event.respondWith(new Response('invalid state', { status: 401, })) return } const token = await this.getToken(code) cookie.deleteCookie(headers, 'oauth.gitea.state') cookie.setCookie(headers, { name: 'oauth.gitea.token', value: token, }) event.respondWith(new Response('', { headers, status: 302, })) } async serve(event) { const {pathname} = new URL(event.request.url) const u = this.baseUrl if (pathname === `${u}/api/auth`) { await this.redirect(event) } else if (pathname === `${u}/api/auth/callback`) { await this.callback(event) } else { event.respondWith(new Response( 'Not Found', {status: 404} )) } } }