@blakearoberts/visage 0.0.1-rc.4 → 0.0.1-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -17
- package/dist/certs.d.ts +1 -2
- package/dist/certs.d.ts.map +1 -1
- package/dist/config.d.ts +29 -35
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +151 -76
- package/dist/types.d.ts +34 -39
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,31 +33,36 @@ Visage is configured through `visage(options?)` in `vite.config.ts`.
|
|
|
33
33
|
|
|
34
34
|
The top-level `host` and `port` configure the local Visage origin that the browser visits:
|
|
35
35
|
|
|
36
|
+
```ts
|
|
37
|
+
visage({ host: 'localhost', port: 9001 });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
### Services
|
|
41
|
+
|
|
42
|
+
Services are Docker Compose services managed by the Vite dev-server lifecycle.
|
|
43
|
+
Additional services automatically get a matching managed upstream with the same
|
|
44
|
+
name, host, and default `/{name}/` location.
|
|
45
|
+
|
|
36
46
|
```ts
|
|
37
47
|
visage({
|
|
38
|
-
|
|
39
|
-
port: 9001,
|
|
48
|
+
services: { whoami: { image: 'traefik/whoami' } },
|
|
40
49
|
});
|
|
41
50
|
```
|
|
42
51
|
|
|
43
|
-
|
|
52
|
+
### Upstreams
|
|
53
|
+
|
|
54
|
+
Upstreams are proxy targets that Visage routes to. A top-level upstream with no
|
|
55
|
+
matching service entry is treated as an external upstream.
|
|
44
56
|
|
|
45
57
|
```ts
|
|
46
58
|
visage({
|
|
47
|
-
services: {
|
|
48
|
-
whoami: { image: 'traefik/whoami' },
|
|
49
|
-
},
|
|
50
59
|
upstreams: {
|
|
51
|
-
|
|
52
|
-
host: 'whoami',
|
|
53
|
-
port: 80,
|
|
54
|
-
locations: { '/whoami/': {} },
|
|
55
|
-
},
|
|
60
|
+
api: { host: 'api.local.test', locations: { '/api/': {} } },
|
|
56
61
|
},
|
|
57
62
|
});
|
|
58
63
|
```
|
|
59
64
|
|
|
60
|
-
See `VisageOptions` for the full option surface.
|
|
65
|
+
See [`VisageOptions`](src/types.ts) for the full option surface.
|
|
61
66
|
|
|
62
67
|
## Expected Local URLs
|
|
63
68
|
|
|
@@ -97,15 +102,17 @@ flowchart LR
|
|
|
97
102
|
|
|
98
103
|
### mkcert
|
|
99
104
|
|
|
100
|
-
Visage downloads [`mkcert`](https://github.com/FiloSottile/mkcert) from `dl.filippo.io` when the Vite dev server starts. Visage uses it to install a local certificate authority and generate HTTPS certificates for the local proxy.
|
|
105
|
+
Visage downloads [`mkcert`](https://github.com/FiloSottile/mkcert) from `dl.filippo.io` into `$XDG_CACHE_HOME/visage/bin/mkcert-<platform>-<arch>` when the Vite dev server starts. Visage uses it to install a local certificate authority and generate HTTPS certificates for the local proxy.
|
|
101
106
|
|
|
102
107
|
### Docker Images
|
|
103
108
|
|
|
104
109
|
Visage pulls these as needed based on configuration:
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
111
|
+
| Service | Image | Source |
|
|
112
|
+
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
113
|
+
| [NGINX](https://nginx.org/) | [`nginx:1.30.0-alpine`](https://hub.docker.com/_/nginx) | Docker Hub |
|
|
114
|
+
| [OAuth2 Proxy](https://oauth2-proxy.github.io/oauth2-proxy/) | [`quay.io/oauth2-proxy/oauth2-proxy:v7.15.2`](https://quay.io/repository/oauth2-proxy/oauth2-proxy) | Quay |
|
|
115
|
+
| [Dex](https://dexidp.io/) | [`ghcr.io/dexidp/dex:v2.45.1`](https://github.com/dexidp/dex/pkgs/container/dex) | GitHub Container Registry |
|
|
109
116
|
|
|
110
117
|
## Security Notes
|
|
111
118
|
|
|
@@ -122,6 +129,7 @@ Do not treat the managed Dex and OAuth2 Proxy defaults as production auth infras
|
|
|
122
129
|
|
|
123
130
|
## TO-DO
|
|
124
131
|
|
|
132
|
+
- [ ] Support SSR injection of identity into HTML responses as script tag elements.
|
|
125
133
|
- [ ] Support configuring [Dex connectors](https://dexidp.io/docs/connectors/).
|
|
126
|
-
- [ ] Support configuring Dex on a distinct subdomain, such as `auth.
|
|
134
|
+
- [ ] Support configuring Dex on a distinct subdomain, such as `auth.localhost`.
|
|
127
135
|
- [ ] Support optional [HTTP mode without local TLS](docs/tls-http-mode.md).
|
package/dist/certs.d.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
type Options = {
|
|
2
|
-
bin: string;
|
|
3
2
|
certs: string;
|
|
4
3
|
hostname: string;
|
|
5
4
|
};
|
|
6
|
-
export declare function ensureCerts({
|
|
5
|
+
export declare function ensureCerts({ certs, hostname }: Options): Promise<void>;
|
|
7
6
|
export {};
|
|
8
7
|
//# sourceMappingURL=certs.d.ts.map
|
package/dist/certs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG;IACb,
|
|
1
|
+
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,WAAW,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAuC7E"}
|
package/dist/config.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ResolvedConfig } from 'vite';
|
|
2
|
-
import type { VisageDexExpiry, VisageDexUser, VisageOptions, VisageService, VisageUpstream } from './types';
|
|
2
|
+
import type { VisageDexExpiry, VisageDexOptions, VisageDexUser, VisageExternalIdpOptions, VisageOptions, VisageService, VisageUpstream } from './types';
|
|
3
3
|
type Volume = readonly [from: string, to: string];
|
|
4
4
|
type ResolvedCookiePolicy = {
|
|
5
5
|
readonly cookie_name: string;
|
|
@@ -8,43 +8,20 @@ type ResolvedCookiePolicy = {
|
|
|
8
8
|
readonly cookie_domains?: readonly string[];
|
|
9
9
|
readonly cookie_path: string;
|
|
10
10
|
};
|
|
11
|
-
type ResolvedDexConfig = {
|
|
12
|
-
readonly expiry?: VisageDexExpiry;
|
|
13
|
-
readonly users: readonly Required<VisageDexUser>[];
|
|
14
|
-
};
|
|
15
11
|
type ResolvedIdpOption = {
|
|
16
|
-
readonly
|
|
17
|
-
|
|
18
|
-
readonly issuer?: string;
|
|
19
|
-
readonly authorizationEndpoint?: string;
|
|
20
|
-
readonly tokenEndpoint?: string;
|
|
21
|
-
readonly jwksEndpoint?: string;
|
|
22
|
-
} & ({
|
|
23
|
-
readonly kind: 'dex';
|
|
24
|
-
readonly dex: ResolvedDexConfig;
|
|
25
|
-
} | {
|
|
26
|
-
readonly kind: 'external';
|
|
27
|
-
});
|
|
28
|
-
type ResolvedIdp = {
|
|
29
|
-
readonly issuer: string;
|
|
30
|
-
readonly authorizationEndpoint: string;
|
|
31
|
-
readonly tokenEndpoint: string;
|
|
32
|
-
readonly jwksEndpoint: string;
|
|
33
|
-
readonly upstream: string;
|
|
34
|
-
} & ({
|
|
35
|
-
readonly kind: 'dex';
|
|
36
|
-
readonly dex: ResolvedDexConfig;
|
|
37
|
-
} | {
|
|
38
|
-
readonly kind: 'external';
|
|
39
|
-
});
|
|
12
|
+
readonly dex: VisageDexOptions;
|
|
13
|
+
} | VisageExternalIdpOptions;
|
|
40
14
|
type ResolvedOAuth2Client = {
|
|
41
15
|
readonly id: string;
|
|
42
16
|
readonly secret?: string;
|
|
43
17
|
readonly scopes: readonly string[];
|
|
44
18
|
readonly public: boolean;
|
|
45
19
|
};
|
|
46
|
-
type
|
|
47
|
-
|
|
20
|
+
type ResolvedService = Omit<VisageService, 'upstream'>;
|
|
21
|
+
type ResolvedUpstream = Omit<VisageUpstream, 'host' | 'port' | 'scheme'> & {
|
|
22
|
+
readonly host: string;
|
|
23
|
+
readonly port: number;
|
|
24
|
+
readonly scheme: 'http' | 'https';
|
|
48
25
|
};
|
|
49
26
|
type ResolvedVisageOptions = {
|
|
50
27
|
readonly host: string;
|
|
@@ -52,14 +29,31 @@ type ResolvedVisageOptions = {
|
|
|
52
29
|
readonly cookie: ResolvedCookiePolicy;
|
|
53
30
|
readonly idp: ResolvedIdpOption;
|
|
54
31
|
readonly oauth2: ResolvedOAuth2Client;
|
|
55
|
-
readonly services
|
|
32
|
+
readonly services: Readonly<Record<string, ResolvedService>>;
|
|
56
33
|
readonly upstreams?: Record<string, ResolvedUpstream>;
|
|
57
34
|
};
|
|
35
|
+
type ResolvedBaseIdpConfig = {
|
|
36
|
+
readonly upstream: string;
|
|
37
|
+
readonly issuer: string;
|
|
38
|
+
readonly authorization: string;
|
|
39
|
+
readonly token: string;
|
|
40
|
+
readonly jwks: string;
|
|
41
|
+
};
|
|
42
|
+
type ResolvedDexIdpConfig = ResolvedBaseIdpConfig & {
|
|
43
|
+
readonly dex: {
|
|
44
|
+
readonly expiry?: VisageDexExpiry;
|
|
45
|
+
readonly users: readonly VisageDexUser[];
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
type ResolvedExternalIdpConfig = ResolvedBaseIdpConfig & {
|
|
49
|
+
readonly dex?: never;
|
|
50
|
+
};
|
|
51
|
+
type ResolvedIdpConfig = ResolvedDexIdpConfig | ResolvedExternalIdpConfig;
|
|
58
52
|
export type VisageConfig = {
|
|
59
53
|
readonly host: string;
|
|
60
54
|
readonly port: number;
|
|
61
55
|
readonly cookie: ResolvedCookiePolicy;
|
|
62
|
-
readonly idp:
|
|
56
|
+
readonly idp: ResolvedIdpConfig;
|
|
63
57
|
readonly oauth2: ResolvedOAuth2Client;
|
|
64
58
|
readonly cache: string;
|
|
65
59
|
readonly files: {
|
|
@@ -70,10 +64,10 @@ export type VisageConfig = {
|
|
|
70
64
|
readonly oauth2Proxy: Volume;
|
|
71
65
|
readonly oauth2ProxyClientSecret: Volume;
|
|
72
66
|
};
|
|
73
|
-
readonly services: Readonly<Record<string,
|
|
67
|
+
readonly services: Readonly<Record<string, ResolvedService>>;
|
|
74
68
|
readonly upstreams: Readonly<Record<string, ResolvedUpstream>>;
|
|
75
69
|
};
|
|
76
|
-
export declare function resolveOptions(
|
|
70
|
+
export declare function resolveOptions(options: VisageOptions): ResolvedVisageOptions;
|
|
77
71
|
export declare function resolveConfig(options: ResolvedVisageOptions, config: ResolvedConfig, vitePort: number): VisageConfig;
|
|
78
72
|
export {};
|
|
79
73
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAE3C,OAAO,KAAK,EACV,eAAe,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Plugin } from 'vite';
|
|
2
2
|
import type { VisageOptions } from './types';
|
|
3
|
-
export type { VisageCookiePolicy, VisageDexExpiry, VisageDexOptions, VisageDexUser,
|
|
3
|
+
export type { VisageCookiePolicy, VisageDexExpiry, VisageDexOptions, VisageDexUser, VisageExternalIdpOptions, VisageOAuth2Client, VisageOptions, VisageProxyPolicy, VisageService, VisageUpstream, } from './types';
|
|
4
4
|
export declare function visage(options?: VisageOptions): Plugin;
|
|
5
5
|
export default visage;
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAOnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAOnC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAE7C,YAAY,EACV,kBAAkB,EAClB,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,wBAAwB,EACxB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AAEjB,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,CAkD1D;AAED,eAAe,MAAM,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { dirname, join } from 'node:path';
|
|
2
2
|
import { spawnSync } from 'node:child_process';
|
|
3
|
-
import { existsSync, mkdirSync,
|
|
3
|
+
import { existsSync, mkdirSync, chmodSync, createWriteStream, readFileSync, appendFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { homedir } from 'node:os';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
6
|
import { pipeline } from 'node:stream/promises';
|
|
@@ -56,18 +56,19 @@ function onSigTerm() {
|
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
async function ensureCerts({
|
|
59
|
+
async function ensureCerts({ certs, hostname }) {
|
|
60
60
|
const cert = join(certs, 'tls.crt');
|
|
61
61
|
const key = join(certs, 'tls.key');
|
|
62
62
|
if (existsSync(cert) && existsSync(key))
|
|
63
63
|
return;
|
|
64
|
-
const mkcert = await ensureMkCert(
|
|
64
|
+
const mkcert = await ensureMkCert();
|
|
65
65
|
const env = {
|
|
66
66
|
...process.env,
|
|
67
67
|
CAROOT: join(process.env.XDG_CACHE_HOME || join(homedir(), '.cache'), 'visage/ca'),
|
|
68
68
|
TRUST_STORES: process.env.TRUST_STORES ?? 'system',
|
|
69
69
|
};
|
|
70
|
-
mkdirSync(env.CAROOT, { recursive: true });
|
|
70
|
+
mkdirSync(env.CAROOT, { recursive: true, mode: 0o700 });
|
|
71
|
+
chmodSync(env.CAROOT, 0o700);
|
|
71
72
|
// mkcert -install is idempotent; CA files alone do not prove trust-store state.
|
|
72
73
|
{
|
|
73
74
|
const result = spawnSync(mkcert, ['-install'], {
|
|
@@ -91,8 +92,9 @@ async function ensureCerts({ bin, certs, hostname, }) {
|
|
|
91
92
|
throw new Error('Failed to generate TLS certificates');
|
|
92
93
|
}
|
|
93
94
|
}
|
|
94
|
-
async function ensureMkCert(
|
|
95
|
-
const
|
|
95
|
+
async function ensureMkCert() {
|
|
96
|
+
const bin = join(process.env.XDG_CACHE_HOME || join(homedir(), '.cache'), 'visage/bin');
|
|
97
|
+
const file = join(bin, `mkcert-${process.platform}-${process.arch}`);
|
|
96
98
|
if (existsSync(file))
|
|
97
99
|
return file;
|
|
98
100
|
mkdirSync(bin, { recursive: true });
|
|
@@ -163,7 +165,7 @@ function renderComposeConfig(config) {
|
|
|
163
165
|
const { dex, nginx, oauth2_proxy, ...services } = config.services;
|
|
164
166
|
return stringify({
|
|
165
167
|
services: {
|
|
166
|
-
...(config.idp.
|
|
168
|
+
...(config.idp.dex !== undefined
|
|
167
169
|
? {
|
|
168
170
|
dex: {
|
|
169
171
|
...config.services.dex,
|
|
@@ -198,14 +200,15 @@ function writeDexConfig(config) {
|
|
|
198
200
|
writeFileSync(file, render, 'utf-8');
|
|
199
201
|
}
|
|
200
202
|
function renderDexConfig(config) {
|
|
201
|
-
|
|
203
|
+
const { idp } = config;
|
|
204
|
+
if (idp.dex === undefined) {
|
|
202
205
|
throw new Error('Dex config is required to render Dex');
|
|
203
206
|
}
|
|
204
207
|
const origin = `https://${config.host}:${config.port}`;
|
|
205
208
|
const redirect = `${origin}/oauth2/callback`;
|
|
206
|
-
const upstream = config.upstreams[
|
|
209
|
+
const upstream = config.upstreams[idp.upstream];
|
|
207
210
|
return stringify({
|
|
208
|
-
issuer:
|
|
211
|
+
issuer: idp.issuer,
|
|
209
212
|
storage: { type: 'memory' },
|
|
210
213
|
web: { http: `0.0.0.0:${upstream.port}` },
|
|
211
214
|
oauth2: { skipApprovalScreen: true },
|
|
@@ -220,10 +223,8 @@ function renderDexConfig(config) {
|
|
|
220
223
|
},
|
|
221
224
|
],
|
|
222
225
|
enablePasswordDB: true,
|
|
223
|
-
...(
|
|
224
|
-
|
|
225
|
-
: { expiry: config.idp.dex.expiry }),
|
|
226
|
-
staticPasswords: config.idp.dex.users.map(({ password, ...user }) => ({
|
|
226
|
+
...(idp.dex.expiry === undefined ? {} : { expiry: idp.dex.expiry }),
|
|
227
|
+
staticPasswords: idp.dex.users.map(({ password, ...user }) => ({
|
|
227
228
|
...user,
|
|
228
229
|
hash: hashSync(password, 10),
|
|
229
230
|
})),
|
|
@@ -314,9 +315,9 @@ function renderOauth2ProxyConfig(config) {
|
|
|
314
315
|
provider: 'oidc',
|
|
315
316
|
oidc_issuer_url: config.idp.issuer,
|
|
316
317
|
skip_oidc_discovery: true,
|
|
317
|
-
login_url: config.idp.
|
|
318
|
-
redeem_url: config.idp.
|
|
319
|
-
oidc_jwks_url: config.idp.
|
|
318
|
+
login_url: config.idp.authorization,
|
|
319
|
+
redeem_url: config.idp.token,
|
|
320
|
+
oidc_jwks_url: config.idp.jwks,
|
|
320
321
|
redirect_url: `https://${config.host}:${config.port}/oauth2/callback`,
|
|
321
322
|
client_id: config.oauth2.id,
|
|
322
323
|
...(config.oauth2.secret === undefined
|
|
@@ -358,7 +359,7 @@ function renderOauth2ProxyConfig(config) {
|
|
|
358
359
|
|
|
359
360
|
function render(config) {
|
|
360
361
|
writeComposeConfig(config);
|
|
361
|
-
if (config.idp.
|
|
362
|
+
if (config.idp.dex !== undefined) {
|
|
362
363
|
writeDexConfig(config);
|
|
363
364
|
}
|
|
364
365
|
writeNginxConfig(config);
|
|
@@ -376,22 +377,23 @@ const BaseFiles = {
|
|
|
376
377
|
],
|
|
377
378
|
oauth2Proxy: ['./oauth2-proxy.yml', '/etc/oauth2-proxy/config.yml'],
|
|
378
379
|
};
|
|
380
|
+
const BaseDexService = {
|
|
381
|
+
image: 'ghcr.io/dexidp/dex:v2.45.1',
|
|
382
|
+
command: ['dex', 'serve', '/etc/dex/dex.yml'],
|
|
383
|
+
};
|
|
384
|
+
const BaseServiceNginx = {
|
|
385
|
+
image: 'nginx:1.30.0-alpine',
|
|
386
|
+
depends_on: ['oauth2_proxy'],
|
|
387
|
+
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
388
|
+
};
|
|
389
|
+
const BaseOAuth2ProxyService = {
|
|
390
|
+
image: 'quay.io/oauth2-proxy/oauth2-proxy:v7.15.2',
|
|
391
|
+
command: ['--config', '/etc/oauth2-proxy/config.yml'],
|
|
392
|
+
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
393
|
+
};
|
|
379
394
|
const BaseServices = {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
command: ['dex', 'serve', '/etc/dex/dex.yml'],
|
|
383
|
-
},
|
|
384
|
-
nginx: {
|
|
385
|
-
image: 'nginx:1.30.0-alpine',
|
|
386
|
-
depends_on: ['oauth2_proxy', 'dex'],
|
|
387
|
-
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
388
|
-
},
|
|
389
|
-
oauth2_proxy: {
|
|
390
|
-
image: 'quay.io/oauth2-proxy/oauth2-proxy:v7.15.2',
|
|
391
|
-
command: ['--config', '/etc/oauth2-proxy/config.yml'],
|
|
392
|
-
depends_on: ['dex'],
|
|
393
|
-
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
394
|
-
},
|
|
395
|
+
nginx: BaseServiceNginx,
|
|
396
|
+
oauth2_proxy: BaseOAuth2ProxyService,
|
|
395
397
|
};
|
|
396
398
|
const BaseDexUpstream = {
|
|
397
399
|
host: 'dex',
|
|
@@ -441,11 +443,6 @@ const DefaultDexUsers = [
|
|
|
441
443
|
password: 'pass',
|
|
442
444
|
},
|
|
443
445
|
];
|
|
444
|
-
const DefaultIdpConfig = {
|
|
445
|
-
kind: 'dex',
|
|
446
|
-
path: '/dex',
|
|
447
|
-
upstream: 'dex',
|
|
448
|
-
};
|
|
449
446
|
const DefaultOAuth2Client = {
|
|
450
447
|
id: 'visage',
|
|
451
448
|
secret: 'visage-secret',
|
|
@@ -460,9 +457,14 @@ const DefaultProxyPolicy = {
|
|
|
460
457
|
'X-Forwarded-Proto': '$scheme',
|
|
461
458
|
},
|
|
462
459
|
};
|
|
463
|
-
function resolveOptions(
|
|
460
|
+
function resolveOptions(options) {
|
|
461
|
+
const { host = 'localhost', port = 9001, cookie = {}, oauth2 = {} } = options;
|
|
464
462
|
const cookieName = cookie.name ?? 'session';
|
|
465
463
|
const publicClient = oauth2.clientSecret === null;
|
|
464
|
+
const upstreams = {
|
|
465
|
+
...resolveServiceUpstreams(options.services),
|
|
466
|
+
...resolveUpstreams(options.upstreams),
|
|
467
|
+
};
|
|
466
468
|
return {
|
|
467
469
|
host,
|
|
468
470
|
port,
|
|
@@ -482,7 +484,7 @@ function resolveOptions({ host = 'local.vite.app', port = 9001, cookie = {}, idp
|
|
|
482
484
|
: { cookie_domains: cookie.domains }),
|
|
483
485
|
...(cookie.path === undefined ? {} : { cookie_path: cookie.path }),
|
|
484
486
|
},
|
|
485
|
-
idp: resolveIdpOption(idp),
|
|
487
|
+
idp: resolveIdpOption(options.idp),
|
|
486
488
|
oauth2: {
|
|
487
489
|
id: oauth2.clientId ?? DefaultOAuth2Client.id,
|
|
488
490
|
...(publicClient
|
|
@@ -491,30 +493,74 @@ function resolveOptions({ host = 'local.vite.app', port = 9001, cookie = {}, idp
|
|
|
491
493
|
scopes: oauth2.scopes ?? DefaultOAuth2Client.scopes,
|
|
492
494
|
public: publicClient,
|
|
493
495
|
},
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
496
|
+
services: {
|
|
497
|
+
...Object.fromEntries(Object.entries(options.services ?? {}).map(([name, service]) => [
|
|
498
|
+
name,
|
|
499
|
+
resolveService(service),
|
|
500
|
+
])),
|
|
501
|
+
nginx: {
|
|
502
|
+
...BaseServiceNginx,
|
|
503
|
+
...{
|
|
504
|
+
...resolveService(options.services?.nginx ?? {}),
|
|
505
|
+
extra_hosts: [
|
|
506
|
+
...BaseServiceNginx.extra_hosts,
|
|
507
|
+
...(options.services?.nginx?.extra_hosts ?? []),
|
|
508
|
+
],
|
|
509
|
+
},
|
|
510
|
+
},
|
|
511
|
+
oauth2_proxy: {
|
|
512
|
+
...BaseOAuth2ProxyService,
|
|
513
|
+
...{
|
|
514
|
+
...resolveService(options.services?.oauth2_proxy ?? {}),
|
|
515
|
+
extra_hosts: [
|
|
516
|
+
...BaseOAuth2ProxyService.extra_hosts,
|
|
517
|
+
...(options.services?.oauth2_proxy?.extra_hosts ?? []),
|
|
518
|
+
],
|
|
519
|
+
},
|
|
520
|
+
},
|
|
521
|
+
},
|
|
522
|
+
...(Object.keys(upstreams).length === 0 ? {} : { upstreams }),
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
function resolveService(service) {
|
|
526
|
+
const { upstream: _upstream, ...resolved } = service;
|
|
527
|
+
return resolved;
|
|
528
|
+
}
|
|
529
|
+
function resolveServiceUpstreams(services = {}) {
|
|
530
|
+
return Object.fromEntries(Object.entries(services)
|
|
531
|
+
.filter(([name]) =>
|
|
532
|
+
// Exclude base services handled separately.
|
|
533
|
+
name !== 'dex' && name !== 'nginx' && name !== 'oauth2_proxy')
|
|
534
|
+
.map(([name, service]) => [
|
|
535
|
+
name,
|
|
536
|
+
resolveUpstream(name, service.upstream ?? {}),
|
|
537
|
+
]));
|
|
538
|
+
}
|
|
539
|
+
function resolveUpstreams(upstreams = {}) {
|
|
540
|
+
return Object.fromEntries(Object.entries(upstreams).map(([name, upstream]) => [
|
|
541
|
+
name,
|
|
542
|
+
resolveUpstream(name, upstream),
|
|
543
|
+
]));
|
|
544
|
+
}
|
|
545
|
+
function resolveUpstream(name, upstream) {
|
|
546
|
+
return {
|
|
547
|
+
...upstream,
|
|
548
|
+
host: upstream.host ?? name,
|
|
549
|
+
locations: upstream.locations ?? { [`/${name}/`]: {} },
|
|
550
|
+
port: upstream.port ?? 80,
|
|
551
|
+
scheme: upstream.scheme ?? 'http',
|
|
503
552
|
};
|
|
504
553
|
}
|
|
505
554
|
function resolveIdpOption(idp) {
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
:
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
const { path = DefaultIdpConfig.path, ...external } = idp;
|
|
514
|
-
return { ...external, path: normalizePath(path) };
|
|
555
|
+
if (idp && 'issuer' in idp) {
|
|
556
|
+
return {
|
|
557
|
+
issuer: idp.issuer,
|
|
558
|
+
authorization: idp.authorization ?? '/auth',
|
|
559
|
+
token: idp.token ?? '/token',
|
|
560
|
+
jwks: idp.jwks ?? '/keys',
|
|
561
|
+
};
|
|
515
562
|
}
|
|
516
563
|
return {
|
|
517
|
-
...DefaultIdpConfig,
|
|
518
564
|
dex: {
|
|
519
565
|
...(idp?.expiry ? { expiry: idp.expiry } : {}),
|
|
520
566
|
users: (idp?.users ?? DefaultDexUsers).map((user) => ({
|
|
@@ -526,45 +572,75 @@ function resolveIdpOption(idp) {
|
|
|
526
572
|
},
|
|
527
573
|
};
|
|
528
574
|
}
|
|
575
|
+
function resolveIdpConfig({ host, port, idp, }) {
|
|
576
|
+
if ('dex' in idp) {
|
|
577
|
+
const issuer = `https://${host}:${port}/dex`;
|
|
578
|
+
const upstream = `http://dex:5556/dex`;
|
|
579
|
+
return {
|
|
580
|
+
upstream: 'dex',
|
|
581
|
+
issuer,
|
|
582
|
+
authorization: `${issuer}/auth`,
|
|
583
|
+
token: `${upstream}/token`,
|
|
584
|
+
jwks: `${upstream}/keys`,
|
|
585
|
+
dex: {
|
|
586
|
+
expiry: idp.dex.expiry,
|
|
587
|
+
users: (idp.dex?.users ?? DefaultDexUsers).map((user) => ({
|
|
588
|
+
email: user.email,
|
|
589
|
+
password: user.password,
|
|
590
|
+
username: user.username ?? user.email.split('@', 1)[0],
|
|
591
|
+
userID: user.userID ?? user.email,
|
|
592
|
+
})),
|
|
593
|
+
},
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
return {
|
|
597
|
+
upstream: 'idp',
|
|
598
|
+
issuer: idp.issuer,
|
|
599
|
+
authorization: idp.issuer + (idp.authorization ?? '/auth'),
|
|
600
|
+
token: idp.issuer + (idp.token ?? '/token'),
|
|
601
|
+
jwks: idp.issuer + (idp.jwks ?? '/keys'),
|
|
602
|
+
};
|
|
603
|
+
}
|
|
604
|
+
function resolveExternalIdpUpstream(idp) {
|
|
605
|
+
const issuer = new URL(idp.issuer);
|
|
606
|
+
return {
|
|
607
|
+
host: issuer.hostname,
|
|
608
|
+
scheme: issuer.protocol === 'https:' ? 'https' : 'http',
|
|
609
|
+
port: Number(issuer.port) || (issuer.protocol === 'https:' ? 443 : 80),
|
|
610
|
+
};
|
|
611
|
+
}
|
|
529
612
|
function resolveConfig(options, config, vitePort) {
|
|
613
|
+
const idp = resolveIdpConfig(options);
|
|
530
614
|
const upstreams = {
|
|
531
615
|
oauth2_proxy: BaseOauth2ProxyUpstream,
|
|
532
616
|
vite: { ...BaseViteUpstream, port: vitePort },
|
|
533
|
-
...(
|
|
617
|
+
...(idp.dex === undefined
|
|
618
|
+
? { idp: resolveExternalIdpUpstream(idp) }
|
|
619
|
+
: { dex: BaseDexUpstream }),
|
|
534
620
|
...options.upstreams,
|
|
535
621
|
};
|
|
536
|
-
const { host: idpHost, port: idpPort, scheme: idpScheme, } = upstreams[options.idp.upstream];
|
|
537
|
-
const origin = `https://${options.host}:${options.port}`;
|
|
538
|
-
const idpOrigin = `${idpScheme}://${idpHost}:${idpPort}`;
|
|
539
|
-
const idpBase = {
|
|
540
|
-
upstream: options.idp.upstream,
|
|
541
|
-
issuer: options.idp.issuer ?? `${origin}${options.idp.path}`,
|
|
542
|
-
authorizationEndpoint: options.idp.authorizationEndpoint ?? `${origin}${options.idp.path}/auth`,
|
|
543
|
-
tokenEndpoint: options.idp.tokenEndpoint ?? `${idpOrigin}${options.idp.path}/token`,
|
|
544
|
-
jwksEndpoint: options.idp.jwksEndpoint ?? `${idpOrigin}${options.idp.path}/keys`,
|
|
545
|
-
};
|
|
546
622
|
return {
|
|
547
623
|
host: options.host,
|
|
548
624
|
port: options.port,
|
|
549
625
|
cookie: options.cookie,
|
|
550
|
-
idp
|
|
551
|
-
? { ...idpBase, kind: 'dex', dex: options.idp.dex }
|
|
552
|
-
: { ...idpBase, kind: 'external' },
|
|
626
|
+
idp,
|
|
553
627
|
oauth2: options.oauth2,
|
|
554
628
|
cache: join(config.cacheDir, 'visage'),
|
|
555
629
|
files: { ...BaseFiles },
|
|
556
630
|
services: {
|
|
557
|
-
...(
|
|
631
|
+
...(idp.dex === undefined
|
|
558
632
|
? BaseServices
|
|
559
633
|
: {
|
|
634
|
+
dex: BaseDexService,
|
|
560
635
|
nginx: {
|
|
561
636
|
...BaseServices.nginx,
|
|
562
|
-
depends_on: ['oauth2_proxy'],
|
|
637
|
+
depends_on: ['dex', 'oauth2_proxy'],
|
|
563
638
|
},
|
|
564
639
|
oauth2_proxy: {
|
|
565
640
|
command: BaseServices.oauth2_proxy.command,
|
|
566
641
|
extra_hosts: BaseServices.oauth2_proxy.extra_hosts,
|
|
567
642
|
image: BaseServices.oauth2_proxy.image,
|
|
643
|
+
depends_on: ['dex'],
|
|
568
644
|
},
|
|
569
645
|
}),
|
|
570
646
|
...options.services,
|
|
@@ -607,7 +683,6 @@ function visage(options = {}) {
|
|
|
607
683
|
async function startVisage(port) {
|
|
608
684
|
const config = resolveConfig(resolvedOptions, server.config, port);
|
|
609
685
|
await ensureCerts({
|
|
610
|
-
bin: join(config.cache, 'bin'),
|
|
611
686
|
certs: join(config.cache, config.files.certs[0]),
|
|
612
687
|
hostname: config.host,
|
|
613
688
|
});
|
package/dist/types.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export type VisageOptions = {
|
|
|
5
5
|
/**
|
|
6
6
|
* Browser-facing hostname for the local Visage HTTPS origin.
|
|
7
7
|
*
|
|
8
|
-
* @defaultValue `'
|
|
8
|
+
* @defaultValue `'localhost'`
|
|
9
9
|
*/
|
|
10
10
|
readonly host?: string;
|
|
11
11
|
/**
|
|
@@ -22,7 +22,7 @@ export type VisageOptions = {
|
|
|
22
22
|
* Identity provider configuration. Omit this to use Visage's managed Dex
|
|
23
23
|
* provider.
|
|
24
24
|
*/
|
|
25
|
-
readonly idp?: VisageDexOptions |
|
|
25
|
+
readonly idp?: VisageDexOptions | VisageExternalIdpOptions;
|
|
26
26
|
/**
|
|
27
27
|
* OAuth2 client settings shared by Dex or an external IdP and OAuth2 Proxy.
|
|
28
28
|
*/
|
|
@@ -78,11 +78,6 @@ export type VisageCookiePolicy = {
|
|
|
78
78
|
* Managed Dex identity provider options.
|
|
79
79
|
*/
|
|
80
80
|
export type VisageDexOptions = {
|
|
81
|
-
/**
|
|
82
|
-
* Selects the managed Dex provider. Omit this for the default managed Dex
|
|
83
|
-
* provider.
|
|
84
|
-
*/
|
|
85
|
-
readonly kind?: 'dex';
|
|
86
81
|
/**
|
|
87
82
|
* Token expiration and rotation settings rendered into the Dex config.
|
|
88
83
|
*/
|
|
@@ -164,45 +159,32 @@ export type VisageDexUser = {
|
|
|
164
159
|
/**
|
|
165
160
|
* External OpenID Connect identity provider options.
|
|
166
161
|
*/
|
|
167
|
-
export type
|
|
168
|
-
/**
|
|
169
|
-
* Selects the external IdP flow.
|
|
170
|
-
*/
|
|
171
|
-
readonly kind: 'external';
|
|
162
|
+
export type VisageExternalIdpOptions = {
|
|
172
163
|
/**
|
|
173
|
-
*
|
|
164
|
+
* OIDC issuer URL used by OAuth2 Proxy.
|
|
174
165
|
*/
|
|
175
|
-
readonly
|
|
166
|
+
readonly issuer: string;
|
|
176
167
|
/**
|
|
177
|
-
*
|
|
168
|
+
* OIDC authorization path appended to
|
|
169
|
+
* {@link VisageExternalIdpOptions.issuer}.
|
|
178
170
|
*
|
|
179
|
-
* @defaultValue
|
|
171
|
+
* @defaultValue '/auth'
|
|
180
172
|
*/
|
|
181
|
-
readonly
|
|
182
|
-
/**
|
|
183
|
-
* OIDC issuer URL. Defaults to the Visage origin plus
|
|
184
|
-
* {@link VisageIdpOptions.path}.
|
|
185
|
-
*/
|
|
186
|
-
readonly issuer?: string;
|
|
173
|
+
readonly authorization?: string;
|
|
187
174
|
/**
|
|
188
|
-
*
|
|
189
|
-
*
|
|
190
|
-
*/
|
|
191
|
-
readonly authorizationEndpoint?: string;
|
|
192
|
-
/**
|
|
193
|
-
* Token endpoint URL used by OAuth2 Proxy.
|
|
175
|
+
* OIDC token endpoint path appended to
|
|
176
|
+
* {@link VisageExternalIdpOptions.issuer}.
|
|
194
177
|
*
|
|
195
|
-
*
|
|
196
|
-
* {@link VisageIdpOptions.path} and `/token`.
|
|
178
|
+
* @defaultValue '/token'
|
|
197
179
|
*/
|
|
198
|
-
readonly
|
|
180
|
+
readonly token?: string;
|
|
199
181
|
/**
|
|
200
|
-
* JWKS endpoint
|
|
182
|
+
* OIDC JWKS endpoint path appended to
|
|
183
|
+
* {@link VisageExternalIdpOptions.issuer}.
|
|
201
184
|
*
|
|
202
|
-
*
|
|
203
|
-
* {@link VisageIdpOptions.path} and `/keys`.
|
|
185
|
+
* @defaultValue '/keys'
|
|
204
186
|
*/
|
|
205
|
-
readonly
|
|
187
|
+
readonly jwks?: string;
|
|
206
188
|
};
|
|
207
189
|
/**
|
|
208
190
|
* OAuth2 client configuration used by OAuth2 Proxy and, for managed Dex, the
|
|
@@ -236,9 +218,11 @@ export type VisageOAuth2Client = {
|
|
|
236
218
|
*/
|
|
237
219
|
export type VisageService = {
|
|
238
220
|
/**
|
|
239
|
-
* Container image reference used for the service.
|
|
221
|
+
* Container image reference used for the service. Required for additional
|
|
222
|
+
* services; defaults to the managed image when overriding `nginx` or
|
|
223
|
+
* `oauth2_proxy`.
|
|
240
224
|
*/
|
|
241
|
-
readonly image
|
|
225
|
+
readonly image?: string;
|
|
242
226
|
/**
|
|
243
227
|
* Optional command override rendered into the Compose service.
|
|
244
228
|
*/
|
|
@@ -251,6 +235,11 @@ export type VisageService = {
|
|
|
251
235
|
* Additional host-to-IP mappings rendered into the Compose service.
|
|
252
236
|
*/
|
|
253
237
|
readonly extra_hosts?: readonly string[];
|
|
238
|
+
/**
|
|
239
|
+
* Optional upstream override for this service. Omit this to create a default
|
|
240
|
+
* upstream from the service name.
|
|
241
|
+
*/
|
|
242
|
+
readonly upstream?: VisageUpstream;
|
|
254
243
|
};
|
|
255
244
|
/**
|
|
256
245
|
* Named proxy target that NGINX routes to for one or more locations.
|
|
@@ -258,8 +247,10 @@ export type VisageService = {
|
|
|
258
247
|
export type VisageUpstream = {
|
|
259
248
|
/**
|
|
260
249
|
* Hostname or Compose service name NGINX should proxy to.
|
|
250
|
+
*
|
|
251
|
+
* @defaultValue The upstream name.
|
|
261
252
|
*/
|
|
262
|
-
readonly host
|
|
253
|
+
readonly host?: string;
|
|
263
254
|
/**
|
|
264
255
|
* URL scheme NGINX should use when proxying to this upstream.
|
|
265
256
|
*
|
|
@@ -268,10 +259,14 @@ export type VisageUpstream = {
|
|
|
268
259
|
readonly scheme?: 'http' | 'https';
|
|
269
260
|
/**
|
|
270
261
|
* Port NGINX should proxy to on {@link VisageUpstream.host}.
|
|
262
|
+
*
|
|
263
|
+
* @defaultValue `80`
|
|
271
264
|
*/
|
|
272
|
-
readonly port
|
|
265
|
+
readonly port?: number;
|
|
273
266
|
/**
|
|
274
267
|
* Path-location policies for this upstream, keyed by NGINX location path.
|
|
268
|
+
*
|
|
269
|
+
* @defaultValue `/{upstreamName}/`
|
|
275
270
|
*/
|
|
276
271
|
readonly locations?: {
|
|
277
272
|
readonly [path: string]: VisageProxyPolicy;
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED