wip: oauth
This commit is contained in:
parent
0dac7b9785
commit
72b13f5265
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -4,3 +4,5 @@ dist
|
|||
.output
|
||||
.nuxt
|
||||
.env
|
||||
|
||||
registered-apps.json
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"packageManager": "pnpm@7.9.0",
|
||||
"scripts": {
|
||||
"build": "nuxi build",
|
||||
|
@ -17,11 +18,13 @@
|
|||
"@iconify-json/twemoji": "^1.1.5",
|
||||
"@nuxtjs/color-mode": "^3.1.8",
|
||||
"@pinia/nuxt": "^0.4.3",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/sanitize-html": "^2.6.2",
|
||||
"@unocss/nuxt": "^0.46.5",
|
||||
"@vueuse/nuxt": "^9.5.0",
|
||||
"eslint": "^8.27.0",
|
||||
"form-data": "^4.0.0",
|
||||
"fs-extra": "^10.1.0",
|
||||
"masto": "^4.6.1",
|
||||
"nuxt": "^3.0.0-rc.13",
|
||||
"pinia": "^2.0.23",
|
||||
|
|
|
@ -8,11 +8,13 @@ specifiers:
|
|||
'@iconify-json/twemoji': ^1.1.5
|
||||
'@nuxtjs/color-mode': ^3.1.8
|
||||
'@pinia/nuxt': ^0.4.3
|
||||
'@types/fs-extra': ^9.0.13
|
||||
'@types/sanitize-html': ^2.6.2
|
||||
'@unocss/nuxt': ^0.46.5
|
||||
'@vueuse/nuxt': ^9.5.0
|
||||
eslint: ^8.27.0
|
||||
form-data: ^4.0.0
|
||||
fs-extra: ^10.1.0
|
||||
masto: ^4.6.1
|
||||
nuxt: ^3.0.0-rc.13
|
||||
pinia: ^2.0.23
|
||||
|
@ -30,11 +32,13 @@ devDependencies:
|
|||
'@iconify-json/twemoji': 1.1.5
|
||||
'@nuxtjs/color-mode': 3.1.8
|
||||
'@pinia/nuxt': 0.4.3_typescript@4.8.4
|
||||
'@types/fs-extra': 9.0.13
|
||||
'@types/sanitize-html': 2.6.2
|
||||
'@unocss/nuxt': 0.46.5
|
||||
'@vueuse/nuxt': 9.5.0_nuxt@3.0.0-rc.13
|
||||
eslint: 8.27.0
|
||||
form-data: 4.0.0
|
||||
fs-extra: 10.1.0
|
||||
masto: 4.6.1
|
||||
nuxt: 3.0.0-rc.13_rmayb2veg2btbq6mbmnyivgasy
|
||||
pinia: 2.0.23_typescript@4.8.4
|
||||
|
@ -1169,6 +1173,12 @@ packages:
|
|||
resolution: {integrity: sha512-WulqXMDUTYAXCjZnk6JtIHPigp55cVtDgDrO2gHRwhyJto21+1zbVCtOYB2L1F9w4qCQ0rOGWBnBe0FNTiEJIQ==}
|
||||
dev: true
|
||||
|
||||
/@types/fs-extra/9.0.13:
|
||||
resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==}
|
||||
dependencies:
|
||||
'@types/node': 18.7.23
|
||||
dev: true
|
||||
|
||||
/@types/json-schema/7.0.11:
|
||||
resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==}
|
||||
dev: true
|
||||
|
|
41
scripts/registerApps.ts
Normal file
41
scripts/registerApps.ts
Normal file
|
@ -0,0 +1,41 @@
|
|||
import fs from 'fs-extra'
|
||||
import type { Client } from 'masto'
|
||||
import { $fetch } from 'ohmyfetch'
|
||||
import { APP_NAME } from '~~/constants'
|
||||
|
||||
const KNOWN_SERVERS = [
|
||||
'mastodon.social',
|
||||
'mas.to',
|
||||
'fosstodon.org',
|
||||
]
|
||||
|
||||
const filename = 'public/registered-apps.json'
|
||||
|
||||
let registeredApps: Record<string, Client> = {}
|
||||
|
||||
if (fs.existsSync(filename))
|
||||
registeredApps = await fs.readJSON(filename)
|
||||
|
||||
for (const server of KNOWN_SERVERS) {
|
||||
if (registeredApps[server])
|
||||
continue
|
||||
|
||||
const app = await $fetch(`https://${server}/api/v1/apps`, {
|
||||
method: 'POST',
|
||||
body: {
|
||||
client_name: APP_NAME,
|
||||
redirect_uris: [
|
||||
'urn:ietf:wg:oauth:2.0:oob',
|
||||
'http://localhost:3000/*',
|
||||
'https://nuxtodon.netlify.app/*',
|
||||
].join('\n'),
|
||||
scopes: 'read write follow push',
|
||||
},
|
||||
})
|
||||
|
||||
registeredApps[server] = app
|
||||
|
||||
console.log(`Registered app for ${server}`)
|
||||
}
|
||||
|
||||
await fs.writeJSON(filename, registeredApps, { spaces: 2, EOL: '\n' })
|
26
server/api/[server]/login.ts
Normal file
26
server/api/[server]/login.ts
Normal file
|
@ -0,0 +1,26 @@
|
|||
import { stringifyQuery } from 'ufo'
|
||||
import { getApp } from '~/server/shared'
|
||||
import { HOST_DOMAIN } from '~/constants'
|
||||
|
||||
export default defineEventHandler(async ({ context, res }) => {
|
||||
const server = context.params.server
|
||||
const app = await getApp(server)
|
||||
|
||||
if (!app) {
|
||||
res.statusCode = 400
|
||||
return `App not registered for server: ${server}`
|
||||
}
|
||||
|
||||
const query = stringifyQuery({
|
||||
client_id: app.client_id,
|
||||
scope: 'read write follow push',
|
||||
redirect_uri: `${HOST_DOMAIN}/api/${server}/oauth`,
|
||||
response_type: 'code',
|
||||
})
|
||||
const url = `https://${server}/oauth/authorize?${query}`
|
||||
|
||||
res.writeHead(302, {
|
||||
Location: url,
|
||||
})
|
||||
res.end()
|
||||
})
|
|
@ -1,21 +1,29 @@
|
|||
import { getQuery } from 'ufo'
|
||||
import { getApp } from '~/server/shared'
|
||||
|
||||
export default defineEventHandler(async (event) => {
|
||||
const server = event.context.params.server
|
||||
const app = await getApp(server)
|
||||
|
||||
if (!app) {
|
||||
event.res.statusCode = 400
|
||||
return `App not registered for server: ${server}`
|
||||
}
|
||||
|
||||
const query = getQuery(event.req.url!)
|
||||
const code = query.code
|
||||
const server = event.context.params.server
|
||||
console.log({ query, server })
|
||||
|
||||
const res = await $fetch(`https://${server}/oauth/token`, {
|
||||
method: 'POST',
|
||||
body: {
|
||||
client_id: 'your_client_id_here',
|
||||
client_secret: 'your_client_secret_here',
|
||||
client_id: app.client_id,
|
||||
client_secret: app.client_secret,
|
||||
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
||||
grant_type: 'authorization_code',
|
||||
code,
|
||||
scope: 'read write follow push',
|
||||
},
|
||||
})
|
||||
|
||||
console.log({ res })
|
||||
})
|
||||
|
|
21
server/shared.ts
Normal file
21
server/shared.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { $fetch } from 'ohmyfetch'
|
||||
|
||||
export interface AppInfo {
|
||||
id: string
|
||||
name: string
|
||||
website: string | null
|
||||
redirect_uri: string
|
||||
client_id: string
|
||||
client_secret: string
|
||||
vapid_key: string
|
||||
}
|
||||
|
||||
export const registeredApps: Record<string, AppInfo> = {}
|
||||
|
||||
const promise = $fetch(process.env.APPS_JSON_URL || 'http://localhost:3000/registered-apps.json')
|
||||
.then(r => Object.assign(registeredApps, r))
|
||||
|
||||
export async function getApp(server: string) {
|
||||
await promise
|
||||
return registeredApps[server]
|
||||
}
|
Loading…
Reference in a new issue