infrastructure-components
Version:
Infrastructure-Components configure the infrastructure of your React-App as part of your React-Components.
238 lines • 13.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const authentication_component_1 = require("./authentication-component");
const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
const iso_libs_1 = require("../libs/iso-libs");
/**
* token handed over to the user's browser, serves as password to encrypt/decrypt the Medium-access token
* @type {string}
*/
exports.IC_WEB_TOKEN = "IC_WEB_TOKEN";
/**
* unique id of the user, comes from the provider (GitHub, Medium, etc)
* @type {string}
*/
exports.IC_USER_ID = 'IC_USER_ID';
exports.EMAIL_CONFIRMATION_PARAM = "confirmationtoken";
exports.EMAIL_PARAM = "email";
exports.PASSWORD_PARAM = "password";
exports.AUTH_STATUS = {
PENDING: "pending",
ACTIVE: "active" // the authentication is active
};
/**
* This is an Express middleware that checks whether there is a cookie in the header that contains valid login
* data
*
* @param req
* @param res
* @param next
* @returns if successful, it calls the next middleware, if not, it throws an exception that causes the
* next error handler to be called
*/
exports.createAuthMiddleware = (clientSecret, onAuthenticated) => (req, res, next) => {
//console.log("createAuthMiddleware", req.universalCookies);
const webtoken = req.universalCookies.get(exports.IC_WEB_TOKEN);
const userId = req.universalCookies.get(exports.IC_USER_ID);
if (webtoken !== undefined && userId !== undefined) {
//console.log("webtoken: ", webtoken);
//console.log("userId: ", userId);
try {
const decoded = jsonwebtoken_1.default.verify(webtoken, clientSecret);
if (decoded !== undefined) {
const { id } = decoded;
//console.log("id: ", id);
// we might have numbers... then the "===" comparison does not work
if (id.toString() === userId.toString()) {
// the token contains the correct id
//console.log("token matches :-)")
onAuthenticated(id.toString());
return next();
}
}
return next(authentication_component_1.AUTH_MESSAGE.FAILED);
//throw new Error("UserId in Token does not match UserId in cookie");
}
catch (err) {
return next(authentication_component_1.AUTH_MESSAGE.FAILED);
//throw new Error(err);
}
}
else {
return next(authentication_component_1.AUTH_MESSAGE.NOTLOGGEDIN);
//throw new Error('No token present!');
}
};
const getEncryptedAccessToken = (id, clientSecret, access_token) => {
const today = new Date();
const expirationDate = new Date(today);
expirationDate.setDate(today.getDate() + 60);
// we use the clientSecret to sign the webtoken
const webtoken = jsonwebtoken_1.default.sign({
id: id,
exp: expirationDate.getTime() / 1000,
}, clientSecret);
// now let's use the webtoken to encrypt the access token
const encryptedAccessToken = jsonwebtoken_1.default.sign({
id: id,
accessToken: access_token,
exp: expirationDate.getTime() / 1000,
}, webtoken);
return {
webtoken: webtoken,
encryptedAccessToken: encryptedAccessToken
};
};
/**
* Use this middleware at the endpoint that is specified as the callback-url.
*
* @param fetchAccessToken function that can be called to fetch the access Token
* @param getUserData function to get the userData, takes as input the response from the accessToken-request
* @param clientSecret
* @param callbackUrl
* @param storeAuthData
* @returns {any}
*/
exports.createCallbackMiddleware = (clientSecret, fetchAccessToken, getUserData, storeAuthData, getAuthData, loginUrl) => function (req, res, next) {
return __awaiter(this, void 0, void 0, function* () {
const path = require('path');
//console.log("THIS IS THE AUTH CALLBACK - authMiddleware");
// we use this middleware also as endpoint for email confirmation, then the token-parameter must be specified
const email_confirmation = req.query[exports.EMAIL_CONFIRMATION_PARAM];
const email_param = req.query[exports.EMAIL_PARAM];
const password_param = req.query[exports.PASSWORD_PARAM];
const page = req.query["page"];
//console.log("received params: ", email_confirmation, email_param, password_param);
if (email_param) {
// get the entry of the database
const authDataList = yield getAuthData(req, // request: any
false, //matchBrowserIdentity -- we do not want to match the browser identity, the user might use another browser to confirm he mail address
exports.IC_USER_ID, // key: string
email_param //val: any,
);
//console.log("retrieved auth-data-list: ", authDataList);
// check whether the user already exists
const parsedAuthDataList = authDataList.map(raw => JSON.parse(raw.jsonData));
// the user logs in with her email and password
if (password_param !== undefined && parsedAuthDataList.length > 0) {
const authData = parsedAuthDataList
.reduce((result, cur) => result !== undefined ? (
// check whether we have a better state!
cur.status == exports.AUTH_STATUS.ACTIVE ? cur : result) : (
// check whether the password is correct
cur.encrypted_password === password_param ? cur : undefined), undefined);
if (authData !== undefined) {
if (authData.status == exports.AUTH_STATUS.PENDING) {
return next(authentication_component_1.AUTH_MESSAGE.VERIFICATIONPENDING);
}
// create a new webtoken, i.e. other browser will be logged out!
const { webtoken, encryptedAccessToken } = getEncryptedAccessToken(email_param, clientSecret, password_param);
// put the encrypted web token into the database, this is user (browser)-specific data!
const storeResult = yield storeAuthData(req, // request: any
exports.IC_USER_ID, // key: string
email_param, //val: any,
Object.assign({}, authData, {
encryptedAccessToken: encryptedAccessToken
}));
req.universalCookies.set(exports.IC_WEB_TOKEN, webtoken, { path: '/' });
req.universalCookies.set(exports.IC_USER_ID, email_param, { path: '/' });
//console.log("store password verified result: ", storeResult);
res.redirect(`${path.join(iso_libs_1.getBasename(), page !== undefined ? page : loginUrl)}?message=${authentication_component_1.AUTH_MESSAGE.SUCCESS}`);
}
else {
//console.log ("could not verify password, ", password_param,email_param);
return next(authentication_component_1.AUTH_MESSAGE.FAILED);
}
return;
}
else if (email_confirmation && parsedAuthDataList.length > 0) {
// the user clicks the link from within the confirmation email
const authData = parsedAuthDataList
.reduce((result, cur) => result !== undefined ? result : (cur.encryptedAccessToken === email_confirmation ? cur : undefined), undefined);
//console.log("retrieved auth-data: ", authData);
if (authData !== undefined) {
const { webtoken, encryptedAccessToken } = getEncryptedAccessToken(email_param, clientSecret, email_confirmation);
// put the encrypted web token into the database, this is user (browser)-specific data!
const storeResult = yield storeAuthData(req, // request: any
exports.IC_USER_ID, // key: string
email_param, //val: any,
Object.assign({}, authData, {
status: exports.AUTH_STATUS.ACTIVE,
encryptedAccessToken: encryptedAccessToken
}));
//console.log("webtoken: ", webtoken, email_param)
req.universalCookies.set(exports.IC_WEB_TOKEN, webtoken, { path: '/' });
req.universalCookies.set(exports.IC_USER_ID, email_param, { path: '/' });
//console.log("store email verified result: ", storeResult);
res.redirect(`${path.join(iso_libs_1.getBasename(), page !== undefined ? page : loginUrl)}?message=${authentication_component_1.AUTH_MESSAGE.MAILVERIFIED}`);
}
else {
//console.log ("could not verify access token, ", email_confirmation,email_param);
return next(authentication_component_1.AUTH_MESSAGE.FAILED);
}
return;
}
}
const { redirectPage, fFetch } = fetchAccessToken(req);
// store the redirectPage in the request for further processing
console.log("redirect to: ", redirectPage);
req["redirectPage"] = redirectPage;
yield fFetch().then(function (resJson) {
return __awaiter(this, void 0, void 0, function* () {
//const { token_type, access_token /*, refresh_token, scope, expires_at */} = resJson;
// try the freshly acquired token and get the user's Medium.com id
yield getUserData(resJson).then(function (data) {
return __awaiter(this, void 0, void 0, function* () {
//console.log("get user data: ", JSON.stringify(data));
const { id, name, username, imageUrl, access_token, email, status } = data;
//console.log("id: ", id);
//console.log("name: ", name);
const { webtoken, encryptedAccessToken } = getEncryptedAccessToken(id, clientSecret, access_token);
//console.log("encryptedAccessToken: ", encryptedAccessToken);
// TODO id may be undefined when the token expired!
//console.log("storeAuthData: ", storeAuthData)
// put the encrypted web token into the database, this is user (browser)-specific data!
const storeResult = yield storeAuthData(req, // request: any
exports.IC_USER_ID, // key: string
id, //val: any,
Object.assign({
/** We only store the encrypted token when we have an active status, i.e. a auth-provider
* we keep it in clear-text for e-mail */
encryptedAccessToken: status === exports.AUTH_STATUS.ACTIVE ? encryptedAccessToken : access_token,
name: name,
username: username,
imageUrl: imageUrl,
email: email,
status: status,
}, password_param ? {
encrypted_password: password_param
} : {}) //jsonData: any
);
//console.log("storeResult: ", storeResult);
// give the webtoken to back to the user - if the account is valid, only!
if (status === exports.AUTH_STATUS.ACTIVE) {
req.universalCookies.set(exports.IC_WEB_TOKEN, webtoken, { path: '/' });
req.universalCookies.set(exports.IC_USER_ID, id, { path: '/' });
}
//console.log("done") //'http://' +path.join(req.headers.host + +
res.redirect(path.join(iso_libs_1.getBasename(), redirectPage));
return;
});
});
});
});
});
};
//# sourceMappingURL=auth-middleware.js.map
;