forked from NotNet/gluestick
add graphql codegen + fix some things
This commit is contained in:
parent
4b00ebbf39
commit
b206220c0d
|
@ -35,3 +35,6 @@ yarn-error.log*
|
|||
next-env.d.ts
|
||||
|
||||
database.db*
|
||||
|
||||
# graphql-codegen
|
||||
src/__generated__
|
||||
|
|
92
README.md
92
README.md
|
@ -7,3 +7,95 @@
|
|||
gluestick is NotNet's one stop shop for authentication and account onboarding. It connects Discord and GitHub OAuth to NotNet's LDAP server (LLDAP), manages email inboxes with Migadu, and configures Tailscale ACLs.
|
||||
|
||||
gluestick is developed in house by [NotNite](https://notnite.com/) and [skip](https://slice.zone/), written in Next.js.
|
||||
|
||||
## Deploying
|
||||
|
||||
Note: gluestick is heavily designed for NotNet specific infrastructure, and as such, may require modification for your use.
|
||||
|
||||
You will need:
|
||||
|
||||
- A recent enough Node.js version
|
||||
- An [LLDAP](https://github.com/lldap/lldap) server
|
||||
- Ports are assumed to not have been changed from the defaults
|
||||
- A [Discord application](https://discord.com/developers/applications) for authentication
|
||||
- Set the redirect URL to `(your domain)/oauth/discord/redirect`
|
||||
|
||||
### Cloning & config
|
||||
|
||||
First, clone the repository:
|
||||
|
||||
```shell
|
||||
git clone https://git.n2.pm/NotNet/gluestick.git
|
||||
cd gluestick
|
||||
```
|
||||
|
||||
After cloning, create an `.env.local` with the following contents (in `key=value` form, separated by newlines):
|
||||
|
||||
- `DISCORD_CLIENT_ID`: the client ID from your Discord application
|
||||
- `DISCORD_CLIENT_SECRET`: the client secret from your Discord application
|
||||
- `DISCORD_ALLOWED_GUILDS`: a comma separated list of guild IDs
|
||||
- Users must be in one of these guilds to register with gluestick
|
||||
- Enable "Advanced > Developer Mode" in your Discord client to copy IDs
|
||||
- `LDAP_HOST`: the IP address or hostname of your LLDAP server
|
||||
- `LDAP_BIND_USER`: the bind user of your LLDAP server
|
||||
- `LDAP_BIND_PASSWORD`: the password of the bind user
|
||||
- `BASE_DOMAIN`: the domain gluestick is deployed on, with a protocol and trailing slash
|
||||
- This domain will be used for OAuth redirects - if you are testing locally, set it to `http://localhost:3000/`
|
||||
|
||||
Example config:
|
||||
|
||||
```env
|
||||
DISCORD_CLIENT_ID=1100257729844621324
|
||||
DISCORD_CLIENT_SECRET=redacted
|
||||
DISCORD_ALLOWED_GUILDS=986268106416611368,805978396974514206
|
||||
|
||||
LDAP_HOST=auth
|
||||
LDAP_BIND_USER=admin
|
||||
LDAP_BIND_PASSWORD=redacted
|
||||
|
||||
BASE_DOMAIN=https://gluestick.n2.pm/
|
||||
```
|
||||
|
||||
### Generating code
|
||||
|
||||
gluestick makes use of code generation from both `prisma` and `graphql-codegen`. Before you can deploy it, you need to run their CLI tools.
|
||||
|
||||
First, install required dependencies:
|
||||
|
||||
```shell
|
||||
npm i
|
||||
```
|
||||
|
||||
Because the LLDAP GraphQL API is locked behind authentication, and of a quirk with `graphl-codegen` configuration files, we need to set a temporary environment variable to generate GraphQL code.
|
||||
|
||||
Run the `get-token.js` helper script and set the environment variable from its output:
|
||||
|
||||
```shell
|
||||
node get-token.js
|
||||
export GRAPHQL_CODEDGEN_AUTH=...
|
||||
```
|
||||
|
||||
Then, generate the GraphQL and database code:
|
||||
|
||||
```shell
|
||||
npm run graphql-codegen
|
||||
npm run prisma-generate
|
||||
```
|
||||
|
||||
### Running
|
||||
|
||||
Now, build and run the server:
|
||||
|
||||
```shell
|
||||
npm run build
|
||||
npm run start
|
||||
```
|
||||
|
||||
## Developing
|
||||
|
||||
You'll want to run these two commands at the same time:
|
||||
|
||||
```shell
|
||||
npm run dev # Next.js hot reload
|
||||
npm run graphql-codegen -- -w # GraphQL hot reload
|
||||
```
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
import { CodegenConfig } from "@graphql-codegen/cli";
|
||||
|
||||
// graphql-codegen doesn't load .env.local, so we have to do it manually
|
||||
import * as dotenv from "dotenv";
|
||||
dotenv.config({ path: ".env.local" });
|
||||
|
||||
const config: CodegenConfig = {
|
||||
schema: {
|
||||
[`http://${process.env.LDAP_HOST}:17170/api/graphql`]: {
|
||||
headers: {
|
||||
// can't make the request automatically (await on top level)
|
||||
Authorization: `Bearer ${process.env.GRAPHQL_CODEGEN_AUTH}`
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
documents: ["src/**/*.ts", "src/**/*.tsx"],
|
||||
generates: {
|
||||
"./src/__generated__/": {
|
||||
preset: "client",
|
||||
plugins: [],
|
||||
presetConfig: {
|
||||
gqlTagName: "gql"
|
||||
}
|
||||
}
|
||||
},
|
||||
ignoreNoDocuments: true
|
||||
};
|
||||
|
||||
export default config;
|
|
@ -0,0 +1,22 @@
|
|||
const dotenv = require("dotenv");
|
||||
dotenv.config({ path: ".env.local" });
|
||||
|
||||
async function main() {
|
||||
const url = `http://${process.env.LDAP_HOST}:17170/auth/simple/login`;
|
||||
|
||||
const req = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: process.env.LDAP_BIND_USER,
|
||||
password: process.env.LDAP_BIND_PASSWORD
|
||||
})
|
||||
});
|
||||
|
||||
const res = await req.json();
|
||||
console.log(res.token);
|
||||
}
|
||||
|
||||
main();
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -6,15 +6,21 @@
|
|||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
"lint": "next lint",
|
||||
"graphql-codegen": "graphql-codegen",
|
||||
"prisma-generate": "prisma generate",
|
||||
"prisma-studio": "prisma studio"
|
||||
},
|
||||
"dependencies": {
|
||||
"@apollo/client": "^3.7.12",
|
||||
"@prisma/client": "^4.13.0",
|
||||
"@types/node": "18.16.0",
|
||||
"@types/react": "18.0.38",
|
||||
"@types/react-dom": "18.0.11",
|
||||
"dotenv": "^16.0.3",
|
||||
"eslint": "8.39.0",
|
||||
"eslint-config-next": "13.3.1",
|
||||
"graphql": "^16.6.0",
|
||||
"ldapts": "^4.2.5",
|
||||
"next": "13.3.1",
|
||||
"react": "18.2.0",
|
||||
|
@ -23,6 +29,8 @@
|
|||
"uuid": "^9.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^3.3.1",
|
||||
"@graphql-codegen/client-preset": "^3.0.1",
|
||||
"@types/uuid": "^9.0.1",
|
||||
"prisma": "^4.13.0"
|
||||
}
|
||||
|
|
191
src/app/icon.svg
191
src/app/icon.svg
|
@ -1,191 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
width="31.999998"
|
||||
height="31.999998"
|
||||
viewBox="0 0 8.4666652 8.4666652"
|
||||
version="1.1"
|
||||
id="svg327"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg">
|
||||
<defs
|
||||
id="defs324" />
|
||||
<g
|
||||
id="layer1">
|
||||
<g
|
||||
id="g1582"
|
||||
style="clip-rule:evenodd;display:none;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
transform="scale(0.26458333)">
|
||||
<clipPath
|
||||
id="_clip1">
|
||||
<rect
|
||||
x="0"
|
||||
y="0"
|
||||
width="32"
|
||||
height="32"
|
||||
id="rect1513" />
|
||||
|
||||
</clipPath>
|
||||
|
||||
<path
|
||||
id="path2704"
|
||||
style="clip-rule:evenodd;display:inline;fill:none;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:round;stroke-miterlimit:1.5;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
d="M 10,6 C 8,6 6,8.000001 6,9 v 14 1 3 h 3 l 1,-1 h 12 l 1,1 h 3 V 24 23 9 C 26,8.000001 24,6 22,6 h -6 z"
|
||||
transform="translate(0,-1)" />
|
||||
|
||||
<rect
|
||||
style="clip-rule:evenodd;display:inline;fill:#777777;fill-opacity:1;fill-rule:evenodd;stroke:#000000;stroke-width:4;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:1.5;stroke-dasharray:none;stroke-opacity:1;paint-order:markers stroke fill"
|
||||
id="rect4044"
|
||||
width="24"
|
||||
height="2"
|
||||
x="4"
|
||||
y="28"
|
||||
ry="0"
|
||||
rx="0" />
|
||||
<path
|
||||
d="M 26,9 C 26,8 24,6 22,6 H 16 C 16,6 12,6 10,6 8,6 6,8 6,9 v 15 h 20 z"
|
||||
style="clip-rule:evenodd;display:inline;fill:#777777;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1524"
|
||||
transform="translate(0,-1)" />
|
||||
<path
|
||||
d="M 20,22 19.989,21 H 12 v 1 H 6 v 4 h 3 l 1,-1 h 12 l 1,1 h 3 v -4 z"
|
||||
style="clip-rule:evenodd;fill:#1a1a1a;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1578" />
|
||||
<circle
|
||||
cx="22"
|
||||
cy="24"
|
||||
r="1"
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="circle1530"
|
||||
transform="translate(0,-17)" />
|
||||
<circle
|
||||
cx="22"
|
||||
cy="24"
|
||||
r="1"
|
||||
style="clip-rule:evenodd;fill:#ffffff;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="circle1534"
|
||||
transform="translate(-12,-17)" />
|
||||
<rect
|
||||
x="12"
|
||||
y="10"
|
||||
width="6"
|
||||
height="1"
|
||||
style="clip-rule:evenodd;fill:#e9a620;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="rect1554"
|
||||
transform="matrix(0.666667,0,0,1,5,-4)" />
|
||||
<rect
|
||||
x="19"
|
||||
y="10"
|
||||
width="1"
|
||||
height="1"
|
||||
style="clip-rule:evenodd;fill:#e9a620;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="rect1558"
|
||||
transform="translate(-1,-4)" />
|
||||
<path
|
||||
d="m 7,19 h 4 v 1 H 7 v 1 h 4 v 1 H 7 v 1 H 6 v -5 h 1 z"
|
||||
style="clip-rule:evenodd;fill:#888888;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1538"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="m 26,18 v 5 h -1 v -1 h -4 v -1 h 4 v -1 h -4 v -1 h 4 v -1 z"
|
||||
style="clip-rule:evenodd;fill:#888888;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1542"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="m 18,11 c 0.55,0 0.997,0.445 1,0.994 V 12 23 H 13 V 12 11.994 C 13.003,11.445 13.45,11 14,11 Z"
|
||||
style="clip-rule:evenodd;fill:#666666;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1546"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="m 21,11 h 3 c 0.552,0 1,0.448 1,1 v 4 c 0,0.55 -0.445,0.997 -0.994,1 H 24 21 c -0.552,0 -1,-0.448 -1,-1 v -4 c 0,-0.552 0.448,-1 1,-1 z"
|
||||
id="path1550"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="m 12,16 c 0,0.552 -0.448,1 -1,1 H 8 C 7.448,17 7,16.552 7,16 v -4 c 0,-0.552 0.448,-1 1,-1 h 3 c 0.55,0 0.997,0.445 1,0.994 V 12 Z"
|
||||
id="path1562"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="M 14.994,18 C 14.445,17.997 14,17.55 14,17 v -4 c 0,-0.552 0.448,-1 1,-1 h 2 c 0.552,0 1,0.448 1,1 v 4 c 0,0.55 -0.445,0.997 -0.994,1 H 17 15 Z"
|
||||
id="path1566"
|
||||
style="clip-rule:evenodd;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
transform="translate(0,-2)" />
|
||||
<path
|
||||
d="m 12,24 h -2 v 2.5 c 0,0.133 0.053,0.26 0.146,0.354 C 10.24,26.947 10.367,27 10.5,27 h 1 c 0.133,0 0.26,-0.053 0.354,-0.146 C 11.947,26.76 12,26.633 12,26.5 Z"
|
||||
style="clip-rule:evenodd;fill:#262626;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1570"
|
||||
transform="translate(-0.0263628,1)" />
|
||||
<path
|
||||
d="m 22,24 h -2 v 2.5 c 0,0.133 0.053,0.26 0.146,0.354 C 20.24,26.947 20.367,27 20.5,27 h 1 c 0.133,0 0.26,-0.053 0.354,-0.146 C 21.947,26.76 22,26.633 22,26.5 Z"
|
||||
style="clip-rule:evenodd;display:none;fill:#262626;fill-rule:evenodd;stroke-linecap:round;stroke-miterlimit:1.5"
|
||||
id="path1574"
|
||||
transform="translate(-0.0171758,1)" />
|
||||
</g>
|
||||
<path
|
||||
id="path3192"
|
||||
style="fill:#afafe9;fill-opacity:1;stroke:none;stroke-width:1.05833;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
d="M 6.5463697,1.4789793 C 6.0670904,1.4803459 5.6637357,1.628841 5.0270828,1.7197915 H 4.8947911 l 0.396875,1.5874998 c 0,0 0.3968755,0.2645835 1.0583332,0.3968749 0.6614576,0.1322916 0.926042,0.5291669 1.3229165,0.79375 0.2118459,0.1412306 0.5368253,0.1315796 0.7937499,0.091984 V 2.5197426 c -0.040284,-0.00394 -0.083861,-0.0062 -0.1322917,-0.0062 -0.5454518,0 -0.1322925,-0.6614585 -1.0583332,-0.9260416 C 6.9977877,1.5079989 6.7642239,1.4783582 6.5463697,1.4789793 Z" />
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;stroke:#000000;stroke-width:0.899228;stroke-linecap:square;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
|
||||
id="rect2807"
|
||||
width="1.7466048"
|
||||
height="6.481462"
|
||||
x="4.5804152"
|
||||
y="-2.4549208"
|
||||
ry="0.46296161"
|
||||
transform="rotate(44.094445)" />
|
||||
<rect
|
||||
style="fill:#ffffff;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
id="rect1071"
|
||||
width="1.5874997"
|
||||
height="4.7624993"
|
||||
x="4.6599679"
|
||||
y="-1.8600227"
|
||||
ry="0"
|
||||
transform="rotate(44.094445)" />
|
||||
<rect
|
||||
style="fill:#afafe9;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
id="rect749"
|
||||
width="1.5874997"
|
||||
height="1.5874999"
|
||||
x="4.6599679"
|
||||
y="-2.3891892"
|
||||
ry="0.52916664"
|
||||
transform="rotate(44.094445)" />
|
||||
<rect
|
||||
style="fill:#ff7f2a;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
id="rect753"
|
||||
width="1.5874997"
|
||||
height="1.0583332"
|
||||
x="4.6599679"
|
||||
y="2.9024765"
|
||||
ry="0.52916658"
|
||||
transform="rotate(44.094445)" />
|
||||
<path
|
||||
style="fill:#ff6600;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
d="M 4.8606341,3.9615115 3.7205016,2.8568606 2.9840677,3.6169489 3.1859169,4.5493186 4.1242001,4.7215998 Z"
|
||||
id="path917" />
|
||||
<path
|
||||
style="fill:#00ffff;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
d="M 3.1859169,4.5493186 4.1242001,4.7215998 3.5718746,5.2916661 2.6335914,5.1193848 2.4317422,4.1870152 2.9840677,3.6169489 Z"
|
||||
id="path973" />
|
||||
<rect
|
||||
style="fill:#afafe9;fill-opacity:1;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
id="rect1680"
|
||||
width="1.5874997"
|
||||
height="0.52916658"
|
||||
x="4.6599679"
|
||||
y="-1.3308557"
|
||||
transform="rotate(44.094445)" />
|
||||
<rect
|
||||
style="fill:#ff7f2a;fill-opacity:1;stroke:none;stroke-width:0.0433012;stroke-linecap:square;paint-order:stroke fill markers"
|
||||
id="rect2805"
|
||||
width="1.5874997"
|
||||
height="0.52916658"
|
||||
x="4.6599679"
|
||||
y="2.9024765"
|
||||
transform="rotate(44.094445)" />
|
||||
</g>
|
||||
</svg>
|
Before Width: | Height: | Size: 7.9 KiB |
|
@ -17,6 +17,10 @@ export default function RootLayout({
|
|||
}) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="icon" href="/icon.svg" />
|
||||
</head>
|
||||
|
||||
<body className={inter.className}>
|
||||
{children}
|
||||
|
||||
|
|
|
@ -1,13 +1,12 @@
|
|||
import styles from "./page.module.css";
|
||||
import Image from "next/image";
|
||||
|
||||
export default function Home() {
|
||||
return (
|
||||
<main className={styles.main}>
|
||||
<img src="/icon.svg" alt="gluestick logo" width="256" />
|
||||
<Image src="/icon.svg" alt="gluestick logo" width="256" height="256" />
|
||||
|
||||
<p>
|
||||
:3
|
||||
<br />
|
||||
<a href="/oauth/discord/login">login debug</a>
|
||||
</p>
|
||||
</main>
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
right: 0;
|
||||
bottom: 0;
|
||||
|
||||
width: 40px;
|
||||
padding: 8px;
|
||||
|
||||
opacity: 30%;
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import React from "react";
|
||||
import styles from "./ColorChanger.module.css";
|
||||
import Image from "next/image";
|
||||
|
||||
const colors = [
|
||||
{
|
||||
|
@ -94,8 +95,10 @@ export default function ColorChanger() {
|
|||
const [current, setCurrent] = React.useState<string>("Monokai Pro");
|
||||
|
||||
return (
|
||||
<img
|
||||
<Image
|
||||
src="/paint.svg"
|
||||
width="64"
|
||||
height="64"
|
||||
alt="paint"
|
||||
title={current}
|
||||
onClick={() => {
|
||||
|
|
103
src/ldap.ts
103
src/ldap.ts
|
@ -1,9 +1,104 @@
|
|||
import { ApolloClient, InMemoryCache } from "@apollo/client";
|
||||
import { Client } from "ldapts";
|
||||
import { setInterval } from "timers/promises";
|
||||
import { gql } from "./__generated__";
|
||||
|
||||
const client = new Client({
|
||||
url: `ldap://${process.env.LDAP_HOST}`
|
||||
type LLDAPAuthResponse = {
|
||||
token: string;
|
||||
refreshToken: string;
|
||||
};
|
||||
|
||||
type LLDAPRefreshResponse = {
|
||||
token: string;
|
||||
};
|
||||
|
||||
let ldapClient: Client | null = null;
|
||||
async function getLdapClient() {
|
||||
if (ldapClient === null) {
|
||||
ldapClient = new Client({
|
||||
url: `ldap://${process.env.LDAP_HOST}:3890`
|
||||
});
|
||||
|
||||
// await client.bind(process.env.LDAP_USER, process.env.LDAP_BIND_PASSWORD);
|
||||
await ldapClient.bind(
|
||||
process.env.LDAP_BIND_USER,
|
||||
process.env.LDAP_BIND_PASSWORD
|
||||
);
|
||||
}
|
||||
|
||||
export default client;
|
||||
return ldapClient;
|
||||
}
|
||||
|
||||
let authResponse: LLDAPAuthResponse | null = null;
|
||||
async function regenAuthToken() {
|
||||
if (authResponse !== null) {
|
||||
const url = `http://${process.env.LDAP_HOST}:17170/auth/refresh`;
|
||||
const req = await fetch(url, {
|
||||
headers: {
|
||||
"Refresh-Token": authResponse.refreshToken
|
||||
}
|
||||
});
|
||||
const res: LLDAPRefreshResponse = await req.json();
|
||||
authResponse.token = res.token;
|
||||
} else {
|
||||
const url = `http://${process.env.LDAP_HOST}:17170/auth/simple/login`;
|
||||
const req = await fetch(url, {
|
||||
method: "POST",
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
},
|
||||
body: JSON.stringify({
|
||||
username: process.env.LDAP_BIND_USER,
|
||||
password: process.env.LDAP_BIND_PASSWORD
|
||||
})
|
||||
});
|
||||
|
||||
authResponse = await req.json();
|
||||
}
|
||||
|
||||
// valid for one day, so refresh every 12 hours
|
||||
setTimeout(regenAuthToken, 12 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
async function getAuthToken() {
|
||||
if (authResponse === null) await regenAuthToken();
|
||||
return authResponse!.token;
|
||||
}
|
||||
|
||||
let graphQLClient: ApolloClient<any> | null = null;
|
||||
let graphQLCache = new InMemoryCache();
|
||||
let graphQLAuthToken: string | null = null;
|
||||
async function getGraphQLClient() {
|
||||
if (authResponse === null) {
|
||||
await regenAuthToken();
|
||||
graphQLAuthToken = authResponse!.token;
|
||||
}
|
||||
|
||||
// We keep track of the auth token we used in the client, so we can
|
||||
// recreate it when it expires/refreshes
|
||||
if (graphQLClient === null || graphQLAuthToken !== authResponse!.token) {
|
||||
graphQLClient = new ApolloClient({
|
||||
uri: `http://${process.env.LDAP_HOST}:17170/api/graphql`,
|
||||
cache: graphQLCache,
|
||||
headers: {
|
||||
Authorization: `Bearer ${authResponse!.token}`
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return graphQLClient;
|
||||
}
|
||||
|
||||
export async function getUsers() {
|
||||
const client = await getGraphQLClient();
|
||||
const query = await client.query({
|
||||
query: gql(`
|
||||
query GetUsers {
|
||||
users {
|
||||
id
|
||||
}
|
||||
}
|
||||
`)
|
||||
});
|
||||
|
||||
return query.data.users;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue