Fix the api endpoints

This commit is contained in:
Kiran 2022-02-17 12:27:50 +05:30
parent 6466c3a59f
commit dc9b150304
10 changed files with 222 additions and 99 deletions

4
.env.example Normal file
View File

@ -0,0 +1,4 @@
NODE_ENV=dev
DATABASE_URL=
APP_URL=http://localhost:4000
ENTITY_ID=http://saml.example.com

6
lib/env.ts Normal file
View File

@ -0,0 +1,6 @@
const config = {
appUrl: process.env.APP_URL || 'http://localhost:4000',
entityId: process.env.ENTITY_ID || 'http://saml.example.com',
}
export default config;

145
package-lock.json generated
View File

@ -9,6 +9,7 @@
"@prisma/client": "^3.7.0",
"axios": "^0.24.0",
"next": "12.0.7",
"node-fetch": "^3.2.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"rsuite": "^5.5.2",
@ -3247,6 +3248,28 @@
"reusify": "^1.0.4"
}
},
"node_modules/fetch-blob": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "paypal",
"url": "https://paypal.me/jimmywarting"
}
],
"dependencies": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
},
"engines": {
"node": "^12.20 || >= 14.13"
}
},
"node_modules/file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -3341,6 +3364,17 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"node_modules/formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"dependencies": {
"fetch-blob": "^3.1.2"
},
"engines": {
"node": ">=12.20.0"
}
},
"node_modules/fraction.js": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
@ -4430,6 +4464,14 @@
}
}
},
"node_modules/next/node_modules/node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"engines": {
"node": "4.x || >=6.0.0"
}
},
"node_modules/next/node_modules/postcss": {
"version": "8.2.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
@ -4455,12 +4497,47 @@
"node": ">=0.10.0"
}
},
"node_modules/node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
"node_modules/node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/jimmywarting"
},
{
"type": "github",
"url": "https://paypal.me/jimmywarting"
}
],
"engines": {
"node": "4.x || >=6.0.0"
"node": ">=10.5.0"
}
},
"node_modules/node-fetch": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.0.tgz",
"integrity": "sha512-8xeimMwMItMw8hRrOl3C9/xzU49HV/yE6ORew/l+dxWimO5A4Ra8ld2rerlJvc/O7et5Z1zrWsPX43v1QBjCxw==",
"dependencies": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/node-fetch"
}
},
"node_modules/node-fetch/node_modules/data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==",
"engines": {
"node": ">= 12"
}
},
"node_modules/node-html-parser": {
@ -6086,6 +6163,14 @@
"node": ">=10.13.0"
}
},
"node_modules/web-streams-polyfill": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==",
"engines": {
"node": ">= 8"
}
},
"node_modules/webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
@ -8655,6 +8740,15 @@
"reusify": "^1.0.4"
}
},
"fetch-blob": {
"version": "3.1.4",
"resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.1.4.tgz",
"integrity": "sha512-Eq5Xv5+VlSrYWEqKrusxY1C3Hm/hjeAsCGVG3ft7pZahlUAChpGZT/Ms1WmSLnEAisEXszjzu/s+ce6HZB2VHA==",
"requires": {
"node-domexception": "^1.0.0",
"web-streams-polyfill": "^3.0.3"
}
},
"file-entry-cache": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
@ -8717,6 +8811,14 @@
"resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
"integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k="
},
"formdata-polyfill": {
"version": "4.0.10",
"resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz",
"integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
"requires": {
"fetch-blob": "^3.1.2"
}
},
"fraction.js": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz",
@ -9502,6 +9604,11 @@
"watchpack": "2.3.0"
},
"dependencies": {
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
},
"postcss": {
"version": "8.2.15",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.2.15.tgz",
@ -9519,10 +9626,27 @@
}
}
},
"node-domexception": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
"integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
},
"node-fetch": {
"version": "2.6.1",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.2.0.tgz",
"integrity": "sha512-8xeimMwMItMw8hRrOl3C9/xzU49HV/yE6ORew/l+dxWimO5A4Ra8ld2rerlJvc/O7et5Z1zrWsPX43v1QBjCxw==",
"requires": {
"data-uri-to-buffer": "^4.0.0",
"fetch-blob": "^3.1.4",
"formdata-polyfill": "^4.0.10"
},
"dependencies": {
"data-uri-to-buffer": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.0.tgz",
"integrity": "sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA=="
}
}
},
"node-html-parser": {
"version": "1.4.9",
@ -10721,6 +10845,11 @@
"graceful-fs": "^4.1.2"
}
},
"web-streams-polyfill": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz",
"integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA=="
},
"webidl-conversions": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",

View File

@ -11,6 +11,7 @@
"@prisma/client": "^3.7.0",
"axios": "^0.24.0",
"next": "12.0.7",
"node-fetch": "^3.2.0",
"react": "17.0.2",
"react-dom": "17.0.2",
"rsuite": "^5.5.2",

View File

@ -1,60 +0,0 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { createCertificate, createIdPMetadataXML } from '../../../utils';
import { IdPMetadata } from '../../../types';
const idpEntityId = 'http://saml.example.com';
const baseUrl = 'http://localhost:4000'; // TODO: Read from .env
// https://boxyhqdemo.onelogin.com/trust/saml2/http-post/sso/a810f17d-48a8-4ac2-ae0f-253c823b272c
// https://dev-8924093.okta.com/app/dev-8924093_jacksondemo_1/exk3u9pl6jx4P9AE15d7/sso/saml
// https://accounts.google.com/o/saml2/idp?idpid=C02frd9s1
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<IdPMetadata>
) {
switch (req.method) {
case 'GET':
return await getMetadata();
case 'POST':
return await downloadMetadata();
default:
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
// Get metadata for an app
async function getMetadata() {
//const {id} = req.query;
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
const metadata = {
certificate: await createCertificate(),
fingerprint: '',
sso_url: `${baseUrl}/saml2/app/${appId}`,
entity_id: idpEntityId,
}
return res.json(metadata);
}
// Download metadata for an app
async function downloadMetadata() {
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
const certificate = await createCertificate();
const idpEntityId = 'http://localhost:4000/sso';
const idpSsoUrl = 'http://localhost:4000/sso';
const xml = await createIdPMetadataXML({
idpEntityId,
idpSsoUrl,
certificate,
});
res.setHeader('Content-type', 'text/xml');
res.setHeader('Content-Disposition', 'attachment; filename="metadata.xml"');
return res.send(xml);
}
}

View File

@ -0,0 +1,37 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { createCertificate, createIdPMetadataXML } from '../../../../utils';
import { IdPMetadata } from '../../../../types';
import stream from 'stream';
import { promisify } from 'util';
import config from '../../../../lib/env'
const pipeline = promisify(stream.pipeline);
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<IdPMetadata | string>
) {
switch (req.method) {
case 'GET':
return await downloadMetadata();
default:
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
// Download metadata for an app
async function downloadMetadata() {
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
const xml = await createIdPMetadataXML({
idpEntityId: config.entityId,
idpSsoUrl: `${config.appUrl}/saml2/app/${appId}`,
certificate: await createCertificate(),
});
res.setHeader('Content-type', 'text/xml');
res.setHeader('Content-Disposition', 'attachment; filename=metadata.xml');
await pipeline(xml, res);
}
}

View File

@ -0,0 +1,32 @@
import type { NextApiRequest, NextApiResponse } from 'next';
import { createCertificate } from '../../../../utils';
import { IdPMetadata } from '../../../../types';
import config from '../../../../lib/env'
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<IdPMetadata | string>
) {
switch (req.method) {
case 'GET':
return await getMetadata();
default:
return res.status(405).end(`Method ${req.method} Not Allowed`);
}
// Get metadata for an app
async function getMetadata() {
//const {id} = req.query;
const appId = '0480c44e-f200-4f72-8af0-a5a57611fd2d';
const metadata = {
certificate: await createCertificate(),
fingerprint: '',
sso_url: `${config.appUrl}/saml2/app/${appId}`,
entity_id: config.entityId,
}
return res.json(metadata);
}
}

View File

@ -1,10 +1,11 @@
import prisma from '../../lib/prisma';
import { GetServerSideProps } from 'next';
import React from 'react';
import { App } from '../../types';
import axios from 'axios';
import { IdPMetadata } from '../../types';
import React, { ChangeEvent, FormEvent, useState } from 'react';
// TODO: Remove this
export const getServerSideProps: GetServerSideProps = async ({ params }) => {
const app = await prisma.app.findUnique({
where: {
@ -34,6 +35,8 @@ const ShowApp: React.FC<{app: App, metadata: IdPMetadata}> = ({app, metadata}) =
<p>sso_url: {metadata.sso_url}</p>
<p>entity_id: {metadata.entity_id}</p>
<p>certificate: {metadata.certificate}</p>
<a href="/api/apps/metadata/download" className="px-3 py-2 text-white bg-red-500 rounded">Download Metadata</a>
</div>
);
};

View File

@ -1,13 +0,0 @@
import type { NextPage } from 'next';
import { useEffect, useRef, useState } from 'react';
import { Sidenav, Nav, Dropdown } from 'rsuite';
const Demo: NextPage = (prop) => {
return (
<div>
<h2>Hello from demo</h2>
</div>
);
};
export default Demo;

View File

@ -32,14 +32,6 @@ const Apps: NextPage = () => {
setMetadata(data);
};
const downloadMetadata = async (e: ChangeEvent<HTMLInputElement>) => {
e.preventDefault();
const {data} = await axios.post('/api/apps/metadata', {
...formData
});
}
return (
<div>
<form onSubmit={createApp} className="px-8 pt-6 pb-8 mb-4 bg-white rounded shadow-md">
@ -64,16 +56,8 @@ const Apps: NextPage = () => {
</label>
</div>
<button type="submit" className="px-4 py-2 text-white bg-blue-500 rounded">Build IdP Metadata</button>
<button type="submit" className="px-4 py-2 text-white bg-blue-500 rounded">Create App</button>
</form>
<button type="button" className="px-3 py-2 text-white bg-red-500 rounded" onClick={downloadMetadata}>Download Metadata</button>
<ul className="px-8 pt-6 pb-8 mb-4 bg-white rounded shadow-md">
<li className="px-2 py-2"><strong>SSO URL:</strong> <br></br> {metadata.sso_url}</li>
<li className="px-2 py-2"><strong>Entity ID:</strong> <br></br> {metadata.entity_id}</li>
<li className="px-2 py-2"><strong>Certificate:</strong> <br></br> {metadata.certificate}</li>
</ul>
</div>
);
};