Skip to content

Commit

Permalink
server -> ts
Browse files Browse the repository at this point in the history
  • Loading branch information
pan261 committed Dec 2, 2021
1 parent a67cda8 commit 1f00759
Show file tree
Hide file tree
Showing 5 changed files with 271 additions and 2 deletions.
14 changes: 14 additions & 0 deletions environment.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
declare global {
namespace NodeJS {
interface ProcessEnv {
FORGE_CLIENT_ID: string;
FORGE_CLIENT_SECRET: string;
FORGE_CALLBACK_URL: string;
PORT: string;
}
}
}

// If this file has no import/export statements (i.e. is a script)
// convert it into a module by adding an empty export statement.
export {}
61 changes: 61 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Configures constants used in the other parts of this app
*/

import { AuthClientThreeLegged } from 'forge-apis';

import * as dotenv from 'dotenv';

dotenv.config({path: '../.env'});

export const ForgeAuthClient = AuthClientThreeLegged;

export const scopes: any = ['bucket:create', 'bucket:read', 'data:read', 'data:create', 'data:write'];


// TODO: add production environment variables

export const authClient = new ForgeAuthClient(
process.env.FORGE_CLIENT_ID,
process.env.FORGE_CLIENT_SECRET,
process.env.FORGE_CALLBACK_URL,
scopes,
true
);

export const fileShareProjectID = "a.YnVzaW5lc3M6cHVyZHVlMjY5NiMyMDIxMTExNTQ2Njg0NTI1MQ";

export const folderMap = {
gantry: {
fusionID: "urn:adsk.wipprod:fs.folder:co.IxiedfeBTOGg6NSIGQhXxQ",
local: "File Share/Gantry"
},
lathe: {
fusionID: "urn:adsk.wipprod:fs.folder:co.FDWCeyBGQX2rv8xSNWo5lg",
local: "File Share/Lathe"
},
mill: {
fusionID: "urn:adsk.wipprod:fs.folder:co.nEihcpHUSW-ZsVzU-__1iw",
local: "File Share/Mill"
},
waterjet: {
fusionID: "urn:adsk.wipprod:fs.folder:co.vJLXAKGbQQayeljr-nwztQ",
local: "File Share/Waterjet"
}
};

export const port = process.env.PORT;
export const forgeClientId = process.env.FORGE_CLIENT_ID;
export const forgeClientSecret = process.env.FORGE_CLIENT_SECRET;
export const forgeCallbackURL = process.env.FORGE_CALLBACK_URL;

// export = {
// authClient: authClient,
// scopes: scopes,
// projectID: fileShareProjectID,
// folderMap: folderMap,
// port: process.env.PORT,
// forgeClientId: process.env.FORGE_CLIENT_ID,
// forgeClientSecret: process.env.FORGE_CLIENT_SECRET,
// forgeCallbackURL: process.env.FORGE_CALLBACK_URL
// }
61 changes: 60 additions & 1 deletion src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion src/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
"forge-apis": "^0.8.6"
},
"devDependencies": {
"@types/dotenv": "^8.2.0",
"@types/express": "^4.17.13",
"@types/forge-apis": "^0.8.2",
"@types/node": "^16.11.11",
"eslint": "^7.32.0",
"eslint-config-standard": "^16.0.3",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^5.1.1"
"eslint-plugin-promise": "^5.1.1",
"typescript": "^4.5.2"
}
}
132 changes: 132 additions & 0 deletions src/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
import express from 'express';
import * as config from './config';


const ForgeAuthClient = require('forge-apis').AuthClientThreeLegged;
/**
* Kevin Pan | pan261@purdue.edu | Last Modified: 11/22/2021
*
* Authentication server used to perform 3-legged auth through browser.
*
* Uses environment variables:
* - FORGE_CLIENT_ID
* - FORGE CLIENT_SECRET
* - FORGE_CALLBACK_URL
* - PORT (defaults to 3000)
*
* These are all configured in config.js
*
*/

let credentials: any = null;
let refreshTime: any = null;
let intervalID: NodeJS.Timeout;
const app = express();

/**
* Creates server with three endpoints:
* 1. /auth
* - navigate to login in to Autodesk and begin auth process
* 2. /callback
* - after consent screen, auth API will redirect headers
* 3. /credentials
* - will return credentials JSON object or null if there isn't one
* @returns express server object
*/
const createServer = () => {

const PORT = config.port || 3000;

if (config.forgeClientId == null || config.forgeClientSecret == null) {
console.error('Missing FORGE_CLIENT_ID or FORGE_CLIENT_SECRET env. variables.');
return;
}

// Endpoint to begin authentication process
app.get('/auth', function (req, res) {
console.log(
'\x1b[96mserver.js::createServer:',
'\x1b[0m/auth endpoint called'
);
res.redirect(config.authClient.generateAuthUrl(""));
});

// Endpoint Forge redirects to after consent screen
app.get('/callback', function (req: any, res: any) {
config.authClient.getToken(req.query.code)
.then((creds) => {
credentials = creds;
refreshTime = creds.expires_in - 300;
res.send('Generated token: ' + credentials.access_token);
console.log(
'\x1b[92mserver.js::createServer:',
'\x1b[0m/callback reached, token generated'
);
})
.then(() => {
// sets refresh() function to run on an interval every 55 minutes
intervalID = setInterval(() => refresh(), refreshTime * 1000); // 55 seconds to ms

// sets timeout for 13 days, before clearing refresh interval and clearing credentials
setTimeout(() => {
credentials = null;
clearInterval(intervalID);
console.log(
'\x1b[93mserver.js::createServer:',
'\x1b[0mRefresh token expiring, need to authenticate again'
);
}, 13 * 24 * 3600 * 1000); // 13 days to ms
})
.catch((err: any) => {
console.error(err);
res.send(err);
});
});

// Endpoint for internal use, to get credentials from our auth server
app.get('/credentials', function (req, res) {
if (credentials) {
console.log(
'\x1b[96mserver.js::createServer:',
'\x1b[0m/credentials endpoint called, credentials returned'
);
res.send(credentials);
} else {
console.log(
'\x1b[93mserver.js::createServer:',
'\x1b[0m/credentials endpoint called, no credentials found'
);
res.send('Need to authenticate at localhost:3000/auth');
}
});

// Default endpoint
app.use((err: any, req: any, res: any, next: any) => {
console.error(err);
res.status(err.statusCode).json(err);
});

const server = app.listen(config.port, () => { console.log(`Server listening on port ${PORT}`); });

return server;
}

/**
* Used internally to refresh tokens automatically
*/
const refresh = () => {
config.authClient.refreshToken(credentials, config.scopes)
.then(creds => {
credentials = creds;
console.log(
'\x1b[92mserver.js::refresh:',
'\x1b[0mnew token generated from refresh token:'
);
console.log(credentials);
})
.catch(err => {
console.log(err);
});
};

createServer();

0 comments on commit 1f00759

Please sign in to comment.