import 'npm:iterator-polyfill' import { define } from '../../../utils.ts' // Polyfill AsyncIterator // import { db } from ':src/db/mod.ts' // import { SessionStore } from ':src/session/mod.ts' // import { respondApi } from ':src/utils.ts' // import { Contact, type Mail, send } from '@cohabit/mailer' // import { magicLinkTemplate } from '@cohabit/mailer/templates' // import { User } from '@cohabit/resources-manager/models' // import { sleep } from '@jotsr/delayed' // type MagicLinkInfos = { // remoteId: string // email: string // timestamp: number // } // export async function getUserByMail(email: string): Promise { // const [user] = await db.resource.user // .list((user) => user.mail === email) // .take(1) // .toArray() // return user // } export const handler = define.handlers({}) // export const _handler = define.handlers({ // async POST(ctx) { // const request = ctx.req // const { email } = await request.json() as { email: string } // // check email before continue // if (!/\S+@\S+\.\S+/.test(email)) { // return respondApi('error', new SyntaxError('empty or invalid email'), 400) // } // const user = await getUserByMail(email) // // generate magic link // const token = crypto.randomUUID() // if (ctx.state.session === undefined) { // return respondApi( // 'error', // new Error('missing server session for current user'), // 500, // ) // } // const remoteAddr = ctx.info.remoteAddr // if (!('hostname' in remoteAddr)) { // return respondApi('error', new Error('connection is not using http'), 500) // } // const endpoint = // `${ctx.url.origin}/api/magiclink?token=${token}&session=${ctx.state.session.uuid}&redirect=/profil` // // save token to session // ctx.state.session.flash(`MAGIC_LINK__${token}`, { // email, // remoteId: remoteId(request, { remoteAddr }), // timestamp: Date.now(), // }) // // send mail to user // try { // if (user) { // // Get user ip through proxy else from tcp connection // const ip = request.headers.get('X-FORWARDED-FOR') ?? remoteAddr.hostname // const device = request.headers.get('Sec-Ch-Ua-Platform') ?? undefined // await sendMagicLink(user, { device, ip, endpoint }) // } else { // //! perform wait to prevent time attacks // await sleep(Math.random() * 5_000 + 2_000) //between 2s and 7s // } // return respondApi('success') // } catch (error) { // console.error('MAGIC_LINK_SENDING', error) // return respondApi( // 'error', // new Error(`unable to send mail to ${email}`), // 500, // ) // } // }, // async GET(ctx) { // const request = ctx.req // const token = ctx.url.searchParams.get('token') // const redirect = ctx.url.searchParams.get('redirect') // const sessionId = ctx.url.searchParams.get('session') // // no token or sessionId // if (token === null || sessionId === null) { // return respondApi('error', 'no token or session provided', 400) // } // // set session if 3rd party cookies was blocked // ctx.state.session = ctx.state.session ?? SessionStore.getSession(sessionId) // // no session available // if (ctx.state.session === null || ctx.state.session === undefined) { // return respondApi('error', 'no session datas', 401) // } // // wrong or timeout token // const entry = ctx.state.session.get(`MAGIC_LINK__${token}`) // const lifespan = Date.now() - 10 * 60 * 1_000 // ten minutes // if (entry === undefined || entry.timestamp < lifespan) { // return respondApi('error', 'wrong token or timeout exceeded', 401) // } // const remoteAddr = ctx.info.remoteAddr // if (!('hostname' in remoteAddr)) { // return respondApi('error', new Error('connection is not using http'), 500) // } // // check remote id (same user/machine that has query the token) // if (entry.remoteId === remoteId(request, { remoteAddr })) { // const user = await getUserByMail(entry.email) // ctx.state.session.set('user', user) // if (redirect) { // return Response.redirect(new URL(redirect, ctx.url.origin)) // } // return respondApi('success', user) // } // return respondApi( // 'error', // new Error( // 'invalid id, use the same device/ip to query token and verify token', // ), // 401, // ) // }, // }) // function remoteId( // { headers }: { headers: Headers }, // { remoteAddr }: { remoteAddr: Deno.NetAddr }, // ): string { // const forwardedAddress = headers.get('X-FORWARDED-FOR') // const forwardedProto = headers.get('X-FORWARDED-PROTO') // if (forwardedAddress && forwardedProto) { // return `${forwardedProto}://${forwardedAddress}` // } // return `(${remoteAddr.transport}):${remoteAddr.hostname}:${remoteAddr.port}` // } // async function sendMagicLink( // { firstname, lastname, mail }: User, // { device, ip, endpoint }: { device?: string; ip?: string; endpoint: string }, // ): Promise { // const message: Mail = { // from: Contact.expand('contact'), // to: [Contact.fromString(`${firstname} ${lastname} <${mail}>`)], // subject: 'Lien de connection pour FabLab Coh@bit', // body: magicLinkTemplate.builder({ // device, // ip, // endpoint, // })!, // options: { // cc: [], // cci: [], // attachments: [], // }, // } // await send(message) // }