forked from woem.men/forkey
implement oauth2 oob
this is necessary for mastodon compatibility fixes #68
This commit is contained in:
parent
e90e9e016f
commit
ad3ae73c53
7 changed files with 2800 additions and 2716 deletions
|
@ -2257,6 +2257,7 @@ _auth:
|
|||
scopeUser: "Operate as the following user"
|
||||
pleaseLogin: "Please log in to authorize applications."
|
||||
byClickingYouWillBeRedirectedToThisUrl: "When access is granted, you will automatically be redirected to the following URL"
|
||||
pleasePassCodeToApplication: "Please pass the following code to the application:"
|
||||
_antennaSources:
|
||||
all: "All notes"
|
||||
homeTimeline: "Notes from followed users"
|
||||
|
|
|
@ -53,7 +53,7 @@ function createMembers(record) {
|
|||
}
|
||||
|
||||
export default function generateDTS() {
|
||||
const locale = yaml.load(fs.readFileSync(`${__dirname}/ja-JP.yml`, 'utf-8'));
|
||||
const locale = yaml.load(fs.readFileSync(`${__dirname}/en-US.yml`, 'utf-8'));
|
||||
const members = createMembers(locale);
|
||||
const elements = [
|
||||
ts.factory.createVariableStatement(
|
||||
|
|
5358
locales/index.d.ts
vendored
5358
locales/index.d.ts
vendored
File diff suppressed because it is too large
Load diff
|
@ -5,6 +5,7 @@
|
|||
|
||||
import dns from 'node:dns/promises';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { request } from 'node:http';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { JSDOM } from 'jsdom';
|
||||
import httpLinkHeader from 'http-link-header';
|
||||
|
@ -509,7 +510,14 @@ export class OAuth2ProviderService {
|
|||
throw new AuthorizationError('Invalid redirect_uri', 'invalid_request');
|
||||
}
|
||||
|
||||
return [null, clientInfo, redirectURI];
|
||||
// Support OAuth2 OOB authentication. This is only supported for Mastodon
|
||||
// clients, as OOB is insecure, however supporting is necessary for
|
||||
// Mastodon compatibility.
|
||||
let newRedirectURI = redirectURI;
|
||||
if (mastodonAppId && redirectURI === 'urn:ietf:wg:oauth:2.0:oob') {
|
||||
newRedirectURI = new URL('/oauth/oob', this.config.url).toString();
|
||||
}
|
||||
return [null, clientInfo, newRedirectURI];
|
||||
})().then(args => done(...args), err => done(err));
|
||||
}) as ValidateFunctionArity2));
|
||||
fastify.use('/authorize', this.#server.errorHandler({
|
||||
|
|
89
packages/frontend/src/components/MkAuthOob.vue
Normal file
89
packages/frontend/src/components/MkAuthOob.vue
Normal file
|
@ -0,0 +1,89 @@
|
|||
<template>
|
||||
<div :class="$style.root" class="_gaps">
|
||||
<div :class="$style.header" class="_gaps_s">
|
||||
<template v-if="props.code">
|
||||
<div :class="$style.iconFallback">
|
||||
<i class="ti ti-check"></i>
|
||||
</div>
|
||||
<div :class="$style.headerText">{{ i18n.ts._auth.accepted }}</div>
|
||||
<div :class="$style.headerTextSub">{{ i18n.ts._auth.pleasePassCodeToApplication }}</div>
|
||||
<div :class="$style.headerTextSub">{{ props.code }}</div>
|
||||
<div class="_buttonsCenter">
|
||||
<MkButton rounded @click="copy">{{ i18n.ts.copy }}</MkButton>
|
||||
</div>
|
||||
</template>
|
||||
<template v-else-if="props.error">
|
||||
<div :class="$style.iconFallback">
|
||||
<i class="ti ti-x"></i>
|
||||
</div>
|
||||
<div :class="$style.headerText">{{ props.error === 'access_denied' ? i18n.ts._auth.denied : props.error }}</div>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import MkButton from '@/components/MkButton.vue';
|
||||
|
||||
import { i18n } from '@/i18n.js';
|
||||
import copyToClipboard from '@/scripts/copy-to-clipboard';
|
||||
|
||||
const props = defineProps<{
|
||||
code: string | null;
|
||||
error: string | null;
|
||||
}>();
|
||||
|
||||
function copy() {
|
||||
copyToClipboard(props.code);
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.root {
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
padding: 48px 24px;
|
||||
}
|
||||
|
||||
.header {
|
||||
margin: 0 auto;
|
||||
max-width: 320px;
|
||||
}
|
||||
|
||||
.icon,
|
||||
.iconFallback {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
width: 54px;
|
||||
height: 54px;
|
||||
}
|
||||
|
||||
.icon {
|
||||
border-radius: 50%;
|
||||
border: 1px solid var(--divider);
|
||||
background-color: #fff;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.iconFallback {
|
||||
border-radius: 50%;
|
||||
background-color: var(--accentedBg);
|
||||
color: var(--accent);
|
||||
text-align: center;
|
||||
line-height: 54px;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.headerText,
|
||||
.headerTextSub {
|
||||
text-align: center;
|
||||
word-break: normal;
|
||||
word-break: auto-phrase;
|
||||
}
|
||||
|
||||
.headerText {
|
||||
font-size: 16px;
|
||||
font-weight: 700;
|
||||
}
|
||||
</style>
|
53
packages/frontend/src/pages/oauth-oob.vue
Normal file
53
packages/frontend/src/pages/oauth-oob.vue
Normal file
|
@ -0,0 +1,53 @@
|
|||
<!--
|
||||
SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
SPDX-License-Identifier: AGPL-3.0-only
|
||||
-->
|
||||
|
||||
<template>
|
||||
<div>
|
||||
<MkAnimBg style="position: fixed; top: 0;"/>
|
||||
<div :class="$style.formContainer">
|
||||
<div :class="$style.form">
|
||||
<MkAuthOob :code="code" :error="error"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
import MkAnimBg from '@/components/MkAnimBg.vue';
|
||||
import { definePageMetadata } from '@/scripts/page-metadata.js';
|
||||
import MkAuthOob from '@/components/MkAuthOob.vue';
|
||||
|
||||
const params = new URLSearchParams(location.search);
|
||||
const code = params.get('code');
|
||||
const error = params.get('error');
|
||||
|
||||
definePageMetadata(() => ({
|
||||
title: 'OAuth',
|
||||
icon: 'ti ti-apps',
|
||||
}));
|
||||
</script>
|
||||
|
||||
<style lang="scss" module>
|
||||
.formContainer {
|
||||
min-height: 100svh;
|
||||
padding: 32px 32px calc(env(safe-area-inset-bottom, 0px) + 32px) 32px;
|
||||
box-sizing: border-box;
|
||||
display: grid;
|
||||
place-content: center;
|
||||
}
|
||||
|
||||
.form {
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
border-radius: var(--radius);
|
||||
background-color: var(--panel);
|
||||
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1);
|
||||
overflow: clip;
|
||||
max-width: 500px;
|
||||
width: calc(100vw - 64px);
|
||||
height: min(65svh, calc(100svh - calc(env(safe-area-inset-bottom, 0px) + 64px)));
|
||||
overflow-y: scroll;
|
||||
}
|
||||
</style>
|
|
@ -270,6 +270,9 @@ const routes: RouteDef[] = [{
|
|||
}, {
|
||||
path: '/oauth/authorize',
|
||||
component: page(() => import('@/pages/oauth.vue')),
|
||||
}, {
|
||||
path: '/oauth/oob',
|
||||
component: page(() => import('@/pages/oauth-oob.vue')),
|
||||
}, {
|
||||
path: '/sso/:kind/:serviceId',
|
||||
component: page(() => import('@/pages/sso.vue')),
|
||||
|
|
Loading…
Reference in a new issue