@treecg/ldes-orchestrator
Version:
Fills the gaps that a Linked Data Platform (LDP) cannot do by itself for creating a Linked Data Event Stream (LDES) in LDP.
136 lines (120 loc) • 4.26 kB
text/typescript
/***************************************
* Title: Login.ts
* Description: TODO
* Author: Wout Slabbinck (wout.slabbinck@ugent.be)
* Created on 26/11/2021
*****************************************/
import {readdirSync, readFileSync, unlinkSync, writeFileSync} from "fs";
import Path from "path";
import {Session, ILoginInputOptions, InMemoryStorage} from "@rubensworks/solid-client-authn-isomorphic";
import {config} from 'dotenv';
import express from "express";
import {sleep} from "./util/Util";
config();
type InputOptions = {
solidIdentityProvider: string;
applicationName?: string;
registrationType: "static" | "dynamic";
};
const validatedOptions: InputOptions = {
applicationName: "LDES-orchestrator",
registrationType: "dynamic",
solidIdentityProvider: process.env.SOLID_IDP!
};
export async function login(): Promise<void> {
const app = express();
const port = 3000;
const iriBase = `http://localhost:${port}`;
const storage = new InMemoryStorage();
const session: Session = new Session({
insecureStorage: storage,
secureStorage: storage,
});
const server = app.listen(port, async () => {
console.log(`Listening at: [${iriBase}].`);
const loginOptions: ILoginInputOptions = {
clientName: validatedOptions.applicationName,
oidcIssuer: validatedOptions.solidIdentityProvider,
redirectUrl: iriBase,
tokenType: "DPoP",
handleRedirect: (url: string) => {
console.log(`\nPlease visit ${url} in a web browser.\n`);
},
};
console.log(
`Logging in to Solid Identity Provider ${validatedOptions.solidIdentityProvider} to get a refresh token.`
);
session.login(loginOptions).catch((e) => {
throw new Error(
`Logging in to Solid Identity Provider [${
validatedOptions.solidIdentityProvider
}] failed: ${e.toString()}`
);
});
});
app.get("/", async (_req: { url: string | URL; }, res: { send: (arg0: string) => void; }) => {
const redirectIri = new URL(_req.url, iriBase).href;
console.log(
`Login into the Identity Provider successful, receiving request to redirect IRI [${redirectIri}].`
);
await session.handleIncomingRedirect(redirectIri);
// NB: This is a temporary approach, and we have work planned to properly
// collect the token. Please note that the next line is not part of the public
// API, and is therefore likely to break on non-major changes.
const rawStoredSession = await storage.get(
`solidClientAuthenticationUser:${session.info.sessionId}`
);
if (rawStoredSession === undefined) {
throw new Error(
`Cannot find session with ID [${session.info.sessionId}] in storage.`
);
}
const storedSession = JSON.parse(rawStoredSession);
console.log(`
These are your login credentials:
{
"refreshToken" : "${storedSession.refreshToken}",
"clientId" : "${storedSession.clientId}",
"clientSecret" : "${storedSession.clientSecret}",
"issuer" : "${storedSession.issuer}",
}
`);
res.send(
"The tokens have been sent to @inrupt/generate-oidc-token. You can close this window."
);
// write session away
writeFileSync(Path.join(__dirname,'config.json'), JSON.stringify(storedSession));
server.close();
});
}
/**
* Function only stops when a config file is created -> indicating that a user is logged in
*/
export async function isLoggedin():Promise<void> {
const rootPath = __dirname;
let loggedIn = false;
while (!loggedIn) {
const files = readdirSync(rootPath);
if (files.includes('config.json')) {
loggedIn = true;
break;
}
await sleep(1000);
}
}
export async function getSession(): Promise<Session> {
const configPath = Path.join(__dirname,'config.json');
const credentials = JSON.parse(readFileSync(configPath, 'utf-8'));
const session = new Session();
session.onNewRefreshToken((newToken: string): void => {
console.log("New refresh token: ", newToken);
});
await session.login({
clientId: credentials.clientId,
clientSecret: credentials.clientSecret,
refreshToken: credentials.refreshToken,
oidcIssuer: credentials.issuer,
});
unlinkSync(configPath);
return session;
}