@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 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
- host: 'localhost',
39
- port: 9001,
48
+ services: { whoami: { image: 'traefik/whoami' } },
40
49
  });
41
50
  ```
42
51
 
43
- Services are Docker Compose services managed by the Vite dev-server lifecycle. Upstreams are proxy targets that Visage routes to, whether they are managed services or external systems.
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
- whoami: {
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
- - [NGINX](https://nginx.org/): [`nginx:1.30.0-alpine`](https://hub.docker.com/_/nginx).
107
- - [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).
108
- - [Dex](https://dexidp.io/): [`ghcr.io/dexidp/dex:v2.45.1`](https://github.com/dexidp/dex/pkgs/container/dex).
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.local.vite.app`.
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({ bin, certs, hostname, }: Options): Promise<void>;
5
+ export declare function ensureCerts({ certs, hostname }: Options): Promise<void>;
7
6
  export {};
8
7
  //# sourceMappingURL=certs.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAOA,KAAK,OAAO,GAAG;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAsB,WAAW,CAAC,EAChC,GAAG,EACH,KAAK,EACL,QAAQ,GACT,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAsCzB"}
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 path: string;
17
- readonly upstream: string;
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 ResolvedUpstream = VisageUpstream & {
47
- readonly scheme: NonNullable<VisageUpstream['scheme']>;
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?: Record<string, VisageService>;
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: ResolvedIdp;
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, VisageService>>;
67
+ readonly services: Readonly<Record<string, ResolvedService>>;
74
68
  readonly upstreams: Readonly<Record<string, ResolvedUpstream>>;
75
69
  };
76
- export declare function resolveOptions({ host, port, cookie, idp, oauth2, services, upstreams, }: VisageOptions): ResolvedVisageOptions;
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
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
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, VisageIdpOptions, VisageOAuth2Client, VisageOptions, VisageProxyPolicy, VisageService, VisageUpstream, } from './types';
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
@@ -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,gBAAgB,EAChB,kBAAkB,EAClB,aAAa,EACb,iBAAiB,EACjB,aAAa,EACb,cAAc,GACf,MAAM,SAAS,CAAC;AAEjB,wBAAgB,MAAM,CAAC,OAAO,GAAE,aAAkB,GAAG,MAAM,CAmD1D;AAED,eAAe,MAAM,CAAC"}
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, createWriteStream, chmodSync, readFileSync, appendFileSync, writeFileSync } from 'node:fs';
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({ bin, certs, hostname, }) {
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(bin);
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(bin) {
95
- const file = join(bin, 'mkcert');
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.kind === 'dex'
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
- if (config.idp.kind !== 'dex') {
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[config.idp.upstream];
209
+ const upstream = config.upstreams[idp.upstream];
207
210
  return stringify({
208
- issuer: config.idp.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
- ...(config.idp.dex.expiry === undefined
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.authorizationEndpoint,
318
- redeem_url: config.idp.tokenEndpoint,
319
- oidc_jwks_url: config.idp.jwksEndpoint,
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.kind === 'dex') {
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
- dex: {
381
- image: 'ghcr.io/dexidp/dex:v2.45.1',
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({ host = 'local.vite.app', port = 9001, cookie = {}, idp, oauth2 = {}, services, upstreams, }) {
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
- ...(services === undefined ? {} : { services }),
495
- ...(upstreams === undefined
496
- ? {}
497
- : {
498
- upstreams: Object.fromEntries(Object.entries(upstreams).map(([name, upstream]) => [
499
- name,
500
- { ...upstream, scheme: upstream.scheme ?? 'http' },
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
- function normalizePath(path) {
507
- const pathWithLeadingSlash = path.startsWith('/') ? path : `/${path}`;
508
- return pathWithLeadingSlash.endsWith('/')
509
- ? pathWithLeadingSlash.slice(0, -1)
510
- : pathWithLeadingSlash;
511
- }
512
- if (idp?.kind === 'external') {
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
- ...(options.idp.kind === 'dex' ? { dex: BaseDexUpstream } : {}),
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: options.idp.kind === 'dex'
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
- ...(options.idp.kind === 'dex'
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 `'local.vite.app'`
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 | VisageIdpOptions;
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 VisageIdpOptions = {
168
- /**
169
- * Selects the external IdP flow.
170
- */
171
- readonly kind: 'external';
162
+ export type VisageExternalIdpOptions = {
172
163
  /**
173
- * Name of the configured upstream that serves the external IdP.
164
+ * OIDC issuer URL used by OAuth2 Proxy.
174
165
  */
175
- readonly upstream: string;
166
+ readonly issuer: string;
176
167
  /**
177
- * Public path where the external IdP is exposed through Visage.
168
+ * OIDC authorization path appended to
169
+ * {@link VisageExternalIdpOptions.issuer}.
178
170
  *
179
- * @defaultValue `'/dex'`
171
+ * @defaultValue '/auth'
180
172
  */
181
- readonly path?: string;
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
- * Browser-facing authorization endpoint URL. Defaults to the Visage origin
189
- * plus {@link VisageIdpOptions.path} and `/auth`.
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
- * Defaults to the configured IdP upstream origin plus
196
- * {@link VisageIdpOptions.path} and `/token`.
178
+ * @defaultValue '/token'
197
179
  */
198
- readonly tokenEndpoint?: string;
180
+ readonly token?: string;
199
181
  /**
200
- * JWKS endpoint URL used by OAuth2 Proxy.
182
+ * OIDC JWKS endpoint path appended to
183
+ * {@link VisageExternalIdpOptions.issuer}.
201
184
  *
202
- * Defaults to the configured IdP upstream origin plus
203
- * {@link VisageIdpOptions.path} and `/keys`.
185
+ * @defaultValue '/keys'
204
186
  */
205
- readonly jwksEndpoint?: string;
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: string;
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: string;
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: number;
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;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blakearoberts/visage",
3
- "version": "0.0.1-rc.4",
3
+ "version": "0.0.1-rc.6",
4
4
  "description": "Vite plugin for local development with HMR and OIDC session cookie lifecycle semantics.",
5
5
  "type": "module",
6
6
  "author": "Blake Roberts",