open-collaboration-server
Version:
Open Collaboration Server implementation, part of the Open Collaboration Tools project
204 lines • 8.55 kB
JavaScript
// ******************************************************************************
// Copyright 2024 TypeFox GmbH
// This program and the accompanying materials are made available under the
// terms of the MIT License, which is available in the project root.
// ******************************************************************************
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
import { inject, injectable, postConstruct } from 'inversify';
import { Emitter, Info } from 'open-collaboration-protocol';
import passport from 'passport';
import { Strategy as GithubStrategy } from 'passport-github';
import { Strategy as GoogleStrategy } from 'passport-google-oauth20';
import { Logger } from '../utils/logging.js';
import { Configuration } from '../utils/configuration.js';
import { URL } from 'url';
export const oauthProviders = Symbol('oauthProviders');
export const ThirdParty = {
code: Info.Codes.ThirdParty,
message: 'Third-party',
params: []
};
let OAuthEndpoint = class OAuthEndpoint {
loginRedirectRequests = new Map();
logger;
configuration;
scope;
baseURL;
authSuccessEmitter = new Emitter();
onDidAuthenticate = this.authSuccessEmitter.event;
initialize() {
this.baseURL = this.configuration.getValue('oct-base-url');
}
onStart(app, hostname, port) {
passport.use(this.id, this.getStrategy(hostname, port));
app.get(this.path, async (req, res) => {
const token = req.query.token;
if (!token) {
this.logger.error('missing token parameter in request');
res.status(400);
res.send('Error: Missing token parameter in request');
return;
}
if (req.query.redirect) {
this.loginRedirectRequests.set(token.toString(), req.query.redirect.toString());
}
passport.authenticate(this.id, { state: `${token}`, scope: this.scope })(req, res);
});
const loginSuccessURL = this.configuration.getValue('oct-login-success-url');
const redirectUriWhitelist = this.configuration.getValue('oct-redirect-url-whitelist')?.split(',');
app.get(this.redirectPath, async (req, res) => {
const token = req.query.state;
if (!token) {
this.logger.error('missing token in request state');
res.status(400);
res.send('Error: Missing token in request state');
return;
}
passport.authenticate(this.id, { state: token, scope: this.scope }, async (err, userInfo) => {
if (err || !userInfo) {
this.logger.error('Error retrieving user info', err);
res.status(400);
res.send('Error retrieving user info');
return;
}
try {
await Promise.all(this.authSuccessEmitter.fire({ token, userInfo }));
}
catch (err) {
this.logger.error('Error during login', err);
res.status(500);
res.send('Internal server error occured during Login. Please try again');
return;
}
const redirectRequest = this.loginRedirectRequests.get(token);
if (redirectRequest) {
this.loginRedirectRequests.delete(token);
if (!redirectUriWhitelist?.includes(redirectRequest)) {
this.logger.error(`Redirect URI ${redirectRequest} not in whitelist`);
res.status(400);
res.send('Error: Redirect URL not in whitelist');
}
else {
const url = URL.canParse(redirectRequest) ? new URL(redirectRequest) : undefined;
if (!url) {
res.status(400);
res.send('Error: Invalid redirect URL');
return;
}
url.searchParams.append('token', token);
res.redirect(url.toString());
}
}
else if (loginSuccessURL) {
res.redirect(loginSuccessURL);
}
else {
res.status(200);
res.send('Login Successful. You can close this page');
}
})(req, res);
});
}
createRedirectUrl(host, port, path) {
const baseURL = this.baseURL ?? `http://${host === '0.0.0.0' ? 'localhost' : host}:${port}`;
return new URL(path, baseURL).toString();
}
};
__decorate([
inject(Logger)
], OAuthEndpoint.prototype, "logger", void 0);
__decorate([
inject(Configuration)
], OAuthEndpoint.prototype, "configuration", void 0);
__decorate([
postConstruct()
], OAuthEndpoint.prototype, "initialize", null);
OAuthEndpoint = __decorate([
injectable()
], OAuthEndpoint);
export { OAuthEndpoint };
let GitHubOAuthEndpoint = class GitHubOAuthEndpoint extends OAuthEndpoint {
id = 'github';
path = '/api/login/github';
redirectPath = '/api/login/github-callback';
shouldActivate() {
return Boolean(this.configuration.getValue('oct-oauth-github-clientid') && this.configuration.getValue('oct-oauth-github-clientsecret'));
}
getProtocolProvider() {
return {
type: 'web',
name: 'github',
endpoint: this.path,
label: {
code: Info.Codes.GitHubLabel,
message: 'GitHub',
params: []
},
group: ThirdParty
};
}
getStrategy(hostname, port) {
return new GithubStrategy({
clientID: this.configuration.getValue('oct-oauth-github-clientid'),
clientSecret: this.configuration.getValue('oct-oauth-github-clientsecret'),
callbackURL: this.createRedirectUrl(hostname, port, this.redirectPath),
}, (accessToken, refreshToken, profile, done) => {
const userInfo = {
name: profile.displayName,
email: profile.emails?.[0]?.value,
authProvider: 'Github'
};
done(undefined, userInfo);
});
}
};
GitHubOAuthEndpoint = __decorate([
injectable()
], GitHubOAuthEndpoint);
export { GitHubOAuthEndpoint };
let GoogleOAuthEndpoint = class GoogleOAuthEndpoint extends OAuthEndpoint {
id = 'google';
path = '/api/login/google';
redirectPath = '/api/login/google-callback';
scope = 'email profile';
shouldActivate() {
return Boolean(this.configuration.getValue('oct-oauth-google-clientid') && this.configuration.getValue('oct-oauth-google-clientsecret'));
}
getProtocolProvider() {
return {
type: 'web',
name: 'google',
endpoint: this.path,
label: {
code: Info.Codes.GoogleLabel,
message: 'Google',
params: []
},
group: ThirdParty
};
}
getStrategy(hostname, port) {
return new GoogleStrategy({
clientID: this.configuration.getValue('oct-oauth-google-clientid'),
clientSecret: this.configuration.getValue('oct-oauth-google-clientsecret'),
callbackURL: this.createRedirectUrl(hostname, port, this.redirectPath),
}, (accessToken, refreshToken, profile, done) => {
const userInfo = {
name: profile.displayName,
email: profile.emails?.find(mail => mail.verified)?.value,
authProvider: 'Google'
};
done(undefined, userInfo);
});
}
};
GoogleOAuthEndpoint = __decorate([
injectable()
], GoogleOAuthEndpoint);
export { GoogleOAuthEndpoint };
//# sourceMappingURL=oauth-endpoint.js.map