-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.ts
136 lines (114 loc) · 4.37 KB
/
main.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
#!/usr/bin/env node
import { Command } from 'commander';
import { createServer, request as httpRequest } from "http";
import httpProxy from "http-proxy";
import UrlPattern from 'url-pattern';
import next from "next";
import { parse } from "url";
import path from "path";
// Check for required environment variables
const requiredEnvVars = [
'NEXT_PUBLIC_STACK_PROJECT_ID',
'NEXT_PUBLIC_STACK_PUBLISHABLE_CLIENT_KEY',
'STACK_SECRET_SERVER_KEY',
'SERVER_PORT',
'PROXY_PORT',
];
for (const envVar of requiredEnvVars) {
if (!process.env[envVar]) {
console.error(`Environment variable ${envVar} is required. Go to https://app.stack-auth.com and create your API keys to continue.`);
process.exit(1);
}
}
const proxyPort = parseInt(process.env.PROXY_PORT!);
const proxyHost = process.env.PROXY_HOST || 'localhost';
const serverPort = parseInt(process.env.SERVER_PORT!);
const serverHost = process.env.SERVER_HOST || 'localhost';
const program = new Command();
program
.description('Auth Proxy\nA simple proxy that authenticates http requests and provide sign-in interface to your app\nAll the routes except /handler/* are forwarded to the server with the user info headers')
.argument('[protectedPattern...]', 'The protected URL patterns (glob syntax)');
program.parse(process.argv);
if (program.args.length === 0) {
console.error('Error: at least one protected pattern is required');
process.exit(1);
}
const dev = process.env.NODE_ENV === "development";
const dir = path.resolve(__dirname, "..");
process.chdir(dir);
const app = next({ dev });
const handle = app.getRequestHandler();
function throwErr(message: string): never {
throw new Error(message);
}
app.prepare().then(() => {
createServer((req, res) => {
let parsedUrl = parse(req.url!, true);
if (new UrlPattern('/handler(/*)').match(parsedUrl.pathname || throwErr("parsedUrl.pathname is undefined"))) {
// This is a hack for the account-setting + next.js basePath incompatibility, should be fixed later in the stack package
if (req.url?.includes("/handler/handler")) {
parsedUrl = parse(req.url.replace("/handler/handler", "/handler"), true);
}
handle(req, res, parsedUrl);
} else {
const options = {
hostname: proxyHost,
port: proxyPort,
path: "/handler/me",
method: "GET",
headers: req.headers,
};
const meReq = httpRequest(options, (meRes) => {
let data = "";
meRes.on("data", (chunk) => {
data += chunk;
});
meRes.on("end", () => {
let userInfo;
try {
userInfo = JSON.parse(data);
} catch (e) {
console.error(e);
res.statusCode = 500;
res.end("Internal server error");
return;
}
const proxy = httpProxy.createProxyServer({});
proxy.on("proxyReq", (proxyReq, req, res) => {
const allHeaders = [
"x-stack-authenticated",
"x-stack-user-id",
"x-stack-user-primary-email",
"x-stack-user-display-name",
];
for (const header of allHeaders) {
proxyReq.removeHeader(header);
}
if (userInfo.authenticated) {
proxyReq.setHeader("x-stack-authenticated", "true");
proxyReq.setHeader("x-stack-user-id", userInfo.user.id);
proxyReq.setHeader("x-stack-user-primary-email", userInfo.user.primary_email);
proxyReq.setHeader("x-stack-user-display-name", userInfo.user.display_name);
} else if (program.args.some((pattern: any) => new UrlPattern(pattern).match(req.url || throwErr("req.url is undefined")))) {
res.statusCode = 302;
res.setHeader("Location", "/handler/sign-in");
res.end();
return;
}
});
proxy.web(req, res, { target: `http://${serverHost}:${serverPort}` });
});
});
meReq.on("error", (err) => {
res.statusCode = 500;
res.end("Internal server error");
});
meReq.end();
}
}).listen(parseInt(process.env.PROXY_PORT!)).on('error', (err) => {
console.error(err);
});
console.log(`Auth Proxy forwarding http://${serverHost}:${serverPort} to http://${proxyHost}:${proxyPort}\nProtecting ${program.args.join(' ')}`);
}).catch((err) => {
console.error(err);
});