Implement /api/website/deny
This commit is contained in:
parent
a4419528a0
commit
c4d3c4d003
9 changed files with 107 additions and 8 deletions
|
@ -2,5 +2,6 @@
|
|||
<project version="4">
|
||||
<component name="JavaScriptLibraryMappings">
|
||||
<file url="file://$PROJECT_DIR$" libraries="{Node.js Core}" />
|
||||
<file url="file://$PROJECT_DIR$/website" libraries="{@mdi/font}" />
|
||||
</component>
|
||||
</project>
|
45
backend/package-lock.json
generated
45
backend/package-lock.json
generated
|
@ -427,6 +427,11 @@
|
|||
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/url-join": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/url-join/-/url-join-4.0.0.tgz",
|
||||
"integrity": "sha512-awrJu8yML4E/xTwr2EMatC+HBnHGoDxc2+ImA9QyeUELI1S7dOCIZcyjki1rkwoA8P2D2NVgLAJLjnclkdLtAw=="
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "7.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.0.tgz",
|
||||
|
@ -2076,11 +2081,41 @@
|
|||
"resolved": "https://registry.npmjs.org/fastify-error/-/fastify-error-0.3.0.tgz",
|
||||
"integrity": "sha512-Jm2LMTB5rsJqlS1+cmgqqM9tTs0UrlgYR7TvDT3ZgXsUI5ib1NjQlqZHf+tDK5tVPdFGwyq02wAoJtyYIRSiFA=="
|
||||
},
|
||||
"fastify-http-proxy": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-http-proxy/-/fastify-http-proxy-4.2.0.tgz",
|
||||
"integrity": "sha512-qxIj5AHrt4sgTVggv1km+dr1105gzHRk39/rhzuNIUy747m2WswsLM+ZeedulK/EGYSTNluKwNhbqwPSZ4JvnA==",
|
||||
"requires": {
|
||||
"fastify-reply-from": "^3.1.3",
|
||||
"ws": "^7.4.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"ws": {
|
||||
"version": "7.4.2",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.2.tgz",
|
||||
"integrity": "sha512-T4tewALS3+qsrpGI/8dqNMLIVdq/g/85U98HPMa6F0m6xTbvhXU6RCQLqPH3+SlomNV/LdY6RXEbBpMH6EOJnA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
"fastify-plugin": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-plugin/-/fastify-plugin-3.0.0.tgz",
|
||||
"integrity": "sha512-ZdCvKEEd92DNLps5n0v231Bha8bkz1DjnPP/aEz37rz/q42Z5JVLmgnqR4DYuNn3NXAO3IDCPyRvgvxtJ4Ym4w=="
|
||||
},
|
||||
"fastify-reply-from": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-reply-from/-/fastify-reply-from-3.5.0.tgz",
|
||||
"integrity": "sha512-kNc0taosEyZz1DZBo/Dt4ihxF210gqalhRAiKFKT0VvGCL/+3A1JunlY/ExeoJUyfiCUWpRJ87pj4FCdrhbZLA==",
|
||||
"requires": {
|
||||
"end-of-stream": "^1.4.1",
|
||||
"fastify-plugin": "^3.0.0",
|
||||
"http-errors": "^1.8.0",
|
||||
"pump": "^3.0.0",
|
||||
"semver": "^7.2.1",
|
||||
"tiny-lru": "^7.0.0",
|
||||
"undici": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"fastify-sensible": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fastify-sensible/-/fastify-sensible-3.1.0.tgz",
|
||||
|
@ -4118,6 +4153,11 @@
|
|||
"random-bytes": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"undici": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/undici/-/undici-2.2.1.tgz",
|
||||
"integrity": "sha512-21sJmMvJOMsyt/2pQPgB5Ruvm2ADTTm34NHRy4kzfeW9uMO7gK2oN0f+5KaJCmoKGJb8KxdU6yWpW0SphFHadw=="
|
||||
},
|
||||
"universalify": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz",
|
||||
|
@ -4131,6 +4171,11 @@
|
|||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"url-join": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz",
|
||||
"integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA=="
|
||||
},
|
||||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
|
|
|
@ -17,11 +17,13 @@
|
|||
"@types/express": "^4.17.10",
|
||||
"@types/lodash": "^4.14.167",
|
||||
"@types/node": "^14.14.21",
|
||||
"@types/url-join": "^4.0.0",
|
||||
"@wulkanowy/sdk": "^0.1.1",
|
||||
"apollo-server-fastify": "^2.19.2",
|
||||
"dotenv": "^8.2.0",
|
||||
"fastify": "^3.10.1",
|
||||
"fastify-cookie": "^5.1.0",
|
||||
"fastify-http-proxy": "^4.2.0",
|
||||
"fastify-sensible": "^3.1.0",
|
||||
"fastify-session": "^5.2.1",
|
||||
"lodash": "^4.17.20",
|
||||
|
@ -32,7 +34,8 @@
|
|||
"ts-node": "^9.1.1",
|
||||
"type-graphql": "^1.1.1",
|
||||
"typeorm": "^0.2.30",
|
||||
"typescript": "^4.1.3"
|
||||
"typescript": "^4.1.3",
|
||||
"url-join": "^4.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@typescript-eslint/eslint-plugin": "^4.13.0",
|
||||
|
|
|
@ -4,3 +4,5 @@ export const scopes = [
|
|||
'notes',
|
||||
'achievements',
|
||||
];
|
||||
|
||||
export const websitePrefix = '/';
|
||||
|
|
|
@ -5,8 +5,10 @@ dotenv.config();
|
|||
|
||||
import Fastify from 'fastify';
|
||||
import FastifyCookie from 'fastify-cookie';
|
||||
import FastifyHttpProxy from 'fastify-http-proxy';
|
||||
import FastifySensible from 'fastify-sensible';
|
||||
import FastifySession from 'fastify-session';
|
||||
import { websitePrefix } from './constants';
|
||||
import database from './database/database';
|
||||
import registerOAuth from './routes/oauth2';
|
||||
import registerWebsiteApi from './routes/website-api';
|
||||
|
@ -28,6 +30,15 @@ async function start() {
|
|||
secure: false, // TODO: Remove this line or add development env variable
|
||||
},
|
||||
});
|
||||
|
||||
const websiteProxyUpstream = process.env.PROXY_WEBSITE;
|
||||
if (websiteProxyUpstream !== undefined) {
|
||||
await server.register(FastifyHttpProxy, {
|
||||
upstream: websiteProxyUpstream,
|
||||
prefix: websitePrefix,
|
||||
});
|
||||
}
|
||||
|
||||
await server.register(registerOAuth, { prefix: '/api/oauth', logLevel: 'info' });
|
||||
await server.register(registerWebsiteApi, { prefix: '/api/website', logLevel: 'info' });
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import _ from 'lodash';
|
||||
import { nanoid } from 'nanoid';
|
||||
import { scopes } from '../../constants';
|
||||
import urlJoin from 'url-join';
|
||||
import { scopes, websitePrefix } from '../../constants';
|
||||
import database from '../../database/database';
|
||||
import { ParamError, ScopeError } from '../../errors';
|
||||
import type { MyFastifyInstance, StudentsMode } from '../../types';
|
||||
|
@ -10,7 +11,7 @@ import {
|
|||
} from '../../utils';
|
||||
|
||||
export default function registerAuthorize(server: MyFastifyInstance): void {
|
||||
server.post('/authorize', async (
|
||||
server.get('/authorize', async (
|
||||
request,
|
||||
reply,
|
||||
) => {
|
||||
|
@ -80,7 +81,7 @@ export default function registerAuthorize(server: MyFastifyInstance): void {
|
|||
studentsMode,
|
||||
});
|
||||
|
||||
await reply.redirect(`/authenticate-prompt?prompt_id=${promptId}`);
|
||||
await reply.redirect(urlJoin(websitePrefix, `/authenticate-prompt?prompt_id=${promptId}`));
|
||||
return;
|
||||
}
|
||||
await reply.redirect(`${request.query.redirect_uri}?error=unsupported_response_type`);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import { ApolloServer } from 'apollo-server-fastify';
|
||||
import { buildSchema } from 'type-graphql';
|
||||
import { ParamError } from '../../errors';
|
||||
import type { ApolloContext, MyFastifyInstance } from '../../types';
|
||||
import { getSessionData } from '../../utils';
|
||||
import { getSessionData, isObject, validateParam } from '../../utils';
|
||||
import LoginResolver from './resolvers/login-resolver';
|
||||
import PromptInfoResolver from './resolvers/prompt-info-resolver';
|
||||
import type { WebsiteAPIContext } from './types';
|
||||
|
@ -26,5 +27,26 @@ export default async function registerWebsiteApi(server: MyFastifyInstance): Pro
|
|||
origin: false,
|
||||
},
|
||||
}));
|
||||
console.log(apolloServer.graphqlPath);
|
||||
|
||||
server.get('/deny', async (
|
||||
request,
|
||||
reply,
|
||||
) => {
|
||||
if (!isObject(request.query)) {
|
||||
server.log.warn('Request query is not an object');
|
||||
throw server.httpErrors.badRequest();
|
||||
}
|
||||
try {
|
||||
validateParam('prompt_id', request.query.prompt_id);
|
||||
} catch (error) {
|
||||
if (error instanceof ParamError) {
|
||||
throw server.httpErrors.badRequest(error.message);
|
||||
}
|
||||
server.log.error(error);
|
||||
throw server.httpErrors.internalServerError();
|
||||
}
|
||||
const prompt = getSessionData(request.session).prompts.get(request.query.prompt_id);
|
||||
if (!prompt) throw server.httpErrors.badRequest('Prompt data not found');
|
||||
await reply.redirect(`${prompt.redirectUri}?error=access_denied&error_description=${encodeURIComponent('User denied')}`);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -7,7 +7,10 @@
|
|||
</div>
|
||||
<v-main class="px-4">
|
||||
<v-sheet max-width="500" class="mx-auto mt-16" color="transparent">
|
||||
<v-alert type="error" text v-if="promptInfoError">
|
||||
<v-alert type="error" text v-if="!promptId">
|
||||
Brak wymaganego parametru <code>prompt_id</code>
|
||||
</v-alert>
|
||||
<v-alert type="error" text v-else-if="promptInfoError">
|
||||
Nie udało się wczytać danych
|
||||
<template #append>
|
||||
<v-btn text color="error" @click="loadPromptInfo">
|
||||
|
@ -97,7 +100,7 @@
|
|||
<v-divider />
|
||||
</div>
|
||||
<v-card-actions>
|
||||
<v-btn color="primary" text outlined>
|
||||
<v-btn color="primary" text outlined :href="denyUrl">
|
||||
Odmów
|
||||
</v-btn>
|
||||
<v-spacer />
|
||||
|
@ -165,6 +168,8 @@ export interface PromptInfo {
|
|||
export default class AuthenticatePromptApp extends Vue {
|
||||
promptInfo: PromptInfo | null = null;
|
||||
|
||||
promptId: string | null = null;
|
||||
|
||||
promptInfoError = false;
|
||||
|
||||
step = 1;
|
||||
|
@ -201,6 +206,11 @@ export default class AuthenticatePromptApp extends Vue {
|
|||
}));
|
||||
}
|
||||
|
||||
get denyUrl() {
|
||||
if (!this.promptId) return undefined;
|
||||
return `/api/website/deny?prompt_id=${this.promptId}`;
|
||||
}
|
||||
|
||||
async loadPromptInfo() {
|
||||
this.promptInfoError = false;
|
||||
this.promptInfo = null;
|
||||
|
@ -222,6 +232,9 @@ export default class AuthenticatePromptApp extends Vue {
|
|||
}
|
||||
|
||||
async created() {
|
||||
const searchParams = new URLSearchParams(window.location.search);
|
||||
this.promptId = searchParams.get('prompt_id');
|
||||
if (!this.promptId) return;
|
||||
await this.loadPromptInfo();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,5 +5,6 @@
|
|||
<content url="file://$MODULE_DIR$" />
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
<orderEntry type="library" name="@mdi/font" level="application" />
|
||||
</component>
|
||||
</module>
|
Loading…
Reference in a new issue