@blakearoberts/visage 0.0.5-rc.2 → 0.0.5-rc.21
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 +15 -21
- package/dist/certs.d.ts.map +1 -1
- package/dist/compose.d.ts.map +1 -1
- package/dist/config.d.ts +1 -2
- package/dist/config.d.ts.map +1 -1
- package/dist/index.js +143 -73
- package/dist/render/compose.d.ts.map +1 -1
- package/dist/render/nginx.d.ts.map +1 -1
- package/dist/types.d.ts +29 -9
- package/dist/types.d.ts.map +1 -1
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -108,13 +108,14 @@ visage({
|
|
|
108
108
|
OAuth2 Proxy identity values can also be mapped explicitly through headers such
|
|
109
109
|
as `$auth_user`, `$auth_email`, `$auth_groups`, and `$auth_preferred_username`.
|
|
110
110
|
|
|
111
|
-
Authenticated locations also get
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
intentionally handles cross-site browser requests itself.
|
|
111
|
+
Authenticated locations also get CSRF checks by default. The policy allows
|
|
112
|
+
same-origin requests and top-level `GET` document navigations, blocks other
|
|
113
|
+
same-site and cross-site browser requests when modern Fetch Metadata headers are
|
|
114
|
+
present, and falls back to an exact `Origin` match or `Referer` origin-prefix
|
|
115
|
+
match against the configured browser origin for unsafe methods when Fetch
|
|
116
|
+
Metadata is absent or unrecognized. Set `csrf: false` when the upstream
|
|
117
|
+
intentionally handles cross-site browser requests itself. See
|
|
118
|
+
[CSRF Policy](../../docs/csrf-policy.md).
|
|
118
119
|
|
|
119
120
|
### External IdPs
|
|
120
121
|
|
|
@@ -175,15 +176,17 @@ terminates local HTTPS, and forwards authenticated identity or token material to
|
|
|
175
176
|
configured upstreams.
|
|
176
177
|
|
|
177
178
|
Please report suspected vulnerabilities through GitHub private vulnerability
|
|
178
|
-
reporting as described in [Security Policy](SECURITY.md).
|
|
179
|
+
reporting as described in [Security Policy](../../SECURITY.md).
|
|
179
180
|
|
|
180
181
|
Do not treat the managed Dex and OAuth2 Proxy defaults as production auth
|
|
181
182
|
infrastructure.
|
|
182
183
|
|
|
183
|
-
Visage's CSRF policy is
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
Visage's CSRF policy is the edge CSRF control for cookie-backed locations.
|
|
185
|
+
Application CSRF tokens are not required for ordinary same-origin SPA mutations
|
|
186
|
+
under this policy. App-level tokens may still be useful when a location disables
|
|
187
|
+
the edge policy, intentionally accepts cross-site browser requests, or needs a
|
|
188
|
+
token that encodes additional authorization semantics. CSP, `frame-ancestors`,
|
|
189
|
+
and other click-jacking controls remain application policy.
|
|
187
190
|
|
|
188
191
|
## Troubleshooting
|
|
189
192
|
|
|
@@ -192,12 +195,3 @@ application accepts form posts or other browser-submitted mutations. CSP,
|
|
|
192
195
|
- If NGINX cannot start, check whether the configured `port` is already in use.
|
|
193
196
|
- If the hostname cannot be resolved, Visage may need permission to update
|
|
194
197
|
`/etc/hosts`.
|
|
195
|
-
|
|
196
|
-
## TO-DO
|
|
197
|
-
|
|
198
|
-
- [ ] Harden the default security posture by addressing the
|
|
199
|
-
[security hardening backlog](docs/security-hardening.md).
|
|
200
|
-
- [ ] Support [runtime config reloads](docs/config-reload.md).
|
|
201
|
-
- [ ] Support [Dex connectors](https://dexidp.io/docs/connectors/).
|
|
202
|
-
- [ ] Support Dex on a distinct subdomain, such as `auth.localhost`.
|
|
203
|
-
- [ ] Support [HTTP mode without local TLS](docs/tls-http-mode.md).
|
package/dist/certs.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"certs.d.ts","sourceRoot":"","sources":["../src/certs.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,wBAAsB,WAAW,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAmCrE"}
|
package/dist/compose.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,IAAI,
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../src/compose.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAE7C,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,IAAI,CA6E7D"}
|
package/dist/config.d.ts
CHANGED
|
@@ -21,9 +21,8 @@ type ResolvedProxyPolicy = {
|
|
|
21
21
|
readonly auth: {
|
|
22
22
|
readonly enabled: boolean;
|
|
23
23
|
readonly forward: false | 'id' | 'access';
|
|
24
|
-
readonly redirect: boolean;
|
|
25
24
|
};
|
|
26
|
-
readonly csrf:
|
|
25
|
+
readonly csrf: boolean;
|
|
27
26
|
readonly headers: Readonly<Record<string, string>>;
|
|
28
27
|
readonly directives: Readonly<Record<string, readonly string[]>>;
|
|
29
28
|
};
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EACV,eAAe,EACf,gBAAgB,EAChB,aAAa,EACb,wBAAwB,EACxB,aAAa,EAEb,aAAa,EAEd,MAAM,SAAS,CAAC;AAEjB,KAAK,MAAM,GAAG,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,CAAC;AAElD,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC5C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF,KAAK,iBAAiB,GACpB;IAAE,QAAQ,CAAC,GAAG,EAAE,gBAAgB,CAAA;CAAE,GAAG,wBAAwB,CAAC;AAEhE,KAAK,oBAAoB,GAAG;IAC1B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,MAAM,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,QAAQ,CAAC,IAAI,EAAE;QACb,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;QAC1B,QAAQ,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,GAAG,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { randomBytes } from 'node:crypto';
|
|
2
2
|
import { basename, resolve, join } from 'node:path';
|
|
3
|
-
import { readFileSync, mkdirSync, chmodSync,
|
|
3
|
+
import { readFileSync, openSync, mkdirSync, chmodSync, rmSync, appendFileSync, writeFileSync } from 'node:fs';
|
|
4
4
|
import { parse, stringify } from 'yaml';
|
|
5
|
-
import { spawnSync } from 'node:child_process';
|
|
6
|
-
import { homedir } from 'node:os';
|
|
5
|
+
import { spawnSync, spawn } from 'node:child_process';
|
|
7
6
|
import { hashSync } from 'bcryptjs';
|
|
8
7
|
import { Eta } from 'eta';
|
|
8
|
+
import { isIP } from 'node:net';
|
|
9
9
|
|
|
10
10
|
const VisageEdgeKeyHeader$1 = 'X-Visage-Edge-Key';
|
|
11
11
|
const DockerImages = parse(readFileSync(new URL('../docker-compose.images.yml', import.meta.url), 'utf8')).services;
|
|
@@ -27,8 +27,8 @@ const BaseServiceOAuth2Proxy = {
|
|
|
27
27
|
restart: 'always',
|
|
28
28
|
};
|
|
29
29
|
const DefaultProxyPolicy = {
|
|
30
|
-
auth: { enabled: true, forward: false
|
|
31
|
-
csrf:
|
|
30
|
+
auth: { enabled: true, forward: false },
|
|
31
|
+
csrf: true,
|
|
32
32
|
headers: {
|
|
33
33
|
Host: '$host',
|
|
34
34
|
// Mitigate header injection by clearing auth headers.
|
|
@@ -53,7 +53,7 @@ const BaseUpstreamOauth2Proxy = {
|
|
|
53
53
|
port: 4180,
|
|
54
54
|
locations: {
|
|
55
55
|
'/oauth2/': {
|
|
56
|
-
auth: { enabled: false, forward: false
|
|
56
|
+
auth: { enabled: false, forward: false },
|
|
57
57
|
csrf: false,
|
|
58
58
|
headers: {
|
|
59
59
|
...DefaultProxyPolicy.headers,
|
|
@@ -63,7 +63,7 @@ const BaseUpstreamOauth2Proxy = {
|
|
|
63
63
|
directives: { ...DefaultProxyPolicy.directives },
|
|
64
64
|
},
|
|
65
65
|
'= /oauth2/auth': {
|
|
66
|
-
auth: { enabled: false, forward: false
|
|
66
|
+
auth: { enabled: false, forward: false },
|
|
67
67
|
csrf: false,
|
|
68
68
|
headers: {
|
|
69
69
|
...DefaultProxyPolicy.headers,
|
|
@@ -77,7 +77,7 @@ const BaseUpstreamOauth2Proxy = {
|
|
|
77
77
|
},
|
|
78
78
|
},
|
|
79
79
|
'/oauth2/sign_out': {
|
|
80
|
-
auth: { enabled: false, forward: false
|
|
80
|
+
auth: { enabled: false, forward: false },
|
|
81
81
|
csrf: false,
|
|
82
82
|
headers: {
|
|
83
83
|
...DefaultProxyPolicy.headers,
|
|
@@ -193,19 +193,14 @@ function resolveUpstreamsOptions(services, upstreams = {}) {
|
|
|
193
193
|
};
|
|
194
194
|
}
|
|
195
195
|
const BaseViteUpstreamRootLocation = {
|
|
196
|
-
auth: { enabled: true, forward: false
|
|
197
|
-
csrf:
|
|
196
|
+
auth: { enabled: true, forward: false },
|
|
197
|
+
csrf: true,
|
|
198
|
+
ws: true,
|
|
198
199
|
headers: {
|
|
199
200
|
Host: '$host',
|
|
200
|
-
Upgrade: '$http_upgrade',
|
|
201
|
-
Connection: '$connection_upgrade',
|
|
202
201
|
'X-Auth-Request-User': '$auth_user',
|
|
203
202
|
'X-Auth-Request-Email': '$auth_email',
|
|
204
203
|
},
|
|
205
|
-
directives: {
|
|
206
|
-
proxy_http_version: ['1.1'],
|
|
207
|
-
proxy_read_timeout: ['1h'],
|
|
208
|
-
},
|
|
209
204
|
};
|
|
210
205
|
function resolveViteUpstreamOptions(upstream) {
|
|
211
206
|
const base = BaseViteUpstreamRootLocation;
|
|
@@ -221,6 +216,7 @@ function resolveViteUpstreamOptions(upstream) {
|
|
|
221
216
|
: {
|
|
222
217
|
auth: { ...base.auth, ...root.auth },
|
|
223
218
|
csrf: root.csrf ?? base.csrf,
|
|
219
|
+
ws: root.ws ?? base.ws,
|
|
224
220
|
headers: {
|
|
225
221
|
...base.headers,
|
|
226
222
|
...root.headers,
|
|
@@ -244,18 +240,22 @@ function resolveUpstreamOptions(name, upstream = {}, external) {
|
|
|
244
240
|
locations: {
|
|
245
241
|
...Object.fromEntries(Object.entries(upstream.locations ?? { [`/${name}/`]: {} }).map(([path, policy]) => [
|
|
246
242
|
path,
|
|
247
|
-
resolveUpstreamLocationOptions(name, host,
|
|
243
|
+
resolveUpstreamLocationOptions(name, host, {
|
|
244
|
+
...policy,
|
|
245
|
+
headers: { ...(upstream.headers ?? {}), ...policy.headers },
|
|
246
|
+
}, external),
|
|
248
247
|
])),
|
|
249
248
|
},
|
|
250
249
|
};
|
|
251
250
|
}
|
|
252
251
|
function resolveUpstreamLocationOptions(name, host, location, external) {
|
|
253
252
|
const auth = resolveAuthPolicy(location.auth, external && name !== 'vite');
|
|
253
|
+
const { ws, ...policy } = location;
|
|
254
254
|
return {
|
|
255
255
|
...DefaultProxyPolicy,
|
|
256
|
-
...
|
|
256
|
+
...policy,
|
|
257
257
|
auth,
|
|
258
|
-
csrf: location.csrf ??
|
|
258
|
+
csrf: location.csrf ?? auth.enabled,
|
|
259
259
|
headers: {
|
|
260
260
|
...DefaultProxyPolicy.headers,
|
|
261
261
|
...(external ? { Host: host } : {}),
|
|
@@ -265,10 +265,22 @@ function resolveUpstreamLocationOptions(name, host, location, external) {
|
|
|
265
265
|
...(auth.enabled && auth.forward === 'access'
|
|
266
266
|
? { Authorization: '"Bearer $access_token"' }
|
|
267
267
|
: {}),
|
|
268
|
+
...(ws
|
|
269
|
+
? {
|
|
270
|
+
Connection: '$connection_upgrade',
|
|
271
|
+
Upgrade: '$http_upgrade',
|
|
272
|
+
}
|
|
273
|
+
: {}),
|
|
268
274
|
...(location.headers ?? {}),
|
|
269
275
|
},
|
|
270
276
|
directives: {
|
|
271
277
|
...DefaultProxyPolicy.directives,
|
|
278
|
+
...(ws
|
|
279
|
+
? {
|
|
280
|
+
proxy_http_version: ['1.1'],
|
|
281
|
+
proxy_read_timeout: ['1h'],
|
|
282
|
+
}
|
|
283
|
+
: {}),
|
|
272
284
|
...Object.fromEntries(Object.entries(location.directives ?? {}).map(([name, value]) => [
|
|
273
285
|
name,
|
|
274
286
|
Array.isArray(value) ? value : [value],
|
|
@@ -284,7 +296,6 @@ function resolveAuthPolicy(auth = {}, external) {
|
|
|
284
296
|
? 'access'
|
|
285
297
|
: 'id'
|
|
286
298
|
: (auth.forward ?? false),
|
|
287
|
-
redirect: auth.redirect ?? false,
|
|
288
299
|
};
|
|
289
300
|
}
|
|
290
301
|
function resolveConfig(options) {
|
|
@@ -402,7 +413,7 @@ function resolveIdpConfig({ host, port, idp, }) {
|
|
|
402
413
|
port: 5556,
|
|
403
414
|
locations: {
|
|
404
415
|
'/dex/': {
|
|
405
|
-
auth: { enabled: false, forward: false
|
|
416
|
+
auth: { enabled: false, forward: false },
|
|
406
417
|
csrf: false,
|
|
407
418
|
headers: { ...DefaultProxyPolicy.headers },
|
|
408
419
|
directives: { ...DefaultProxyPolicy.directives },
|
|
@@ -465,20 +476,15 @@ function isVisageEdgeRequest(request, edgeKey) {
|
|
|
465
476
|
return typeof header === 'string' && header === edgeKey;
|
|
466
477
|
}
|
|
467
478
|
|
|
468
|
-
const CACHE_HOME = process.env.XDG_CACHE_HOME || join(homedir(), '.cache');
|
|
469
479
|
async function ensureCerts(config) {
|
|
470
|
-
const CAROOT = join(CACHE_HOME, 'visage/ca');
|
|
471
|
-
mkdirSync(CAROOT, { recursive: true, mode: 0o700 });
|
|
472
|
-
chmodSync(CAROOT, 0o700);
|
|
473
480
|
const mkcert = resolveMkcert();
|
|
474
481
|
const out = openSync(join(config.cache, 'logs', 'mkcert.log'), 'w');
|
|
475
|
-
const env = { CAROOT, TRUST_STORES: 'system', ...process.env };
|
|
476
482
|
const tty = process.stdin.isTTY;
|
|
477
483
|
const stdio = [tty ? 'inherit' : 'ignore', out, out];
|
|
478
|
-
|
|
484
|
+
{
|
|
479
485
|
// mkcert -install is idempotent;
|
|
480
486
|
// CA files alone don't prove trust-store state.
|
|
481
|
-
const result = spawnSync(mkcert, ['-install'], {
|
|
487
|
+
const result = spawnSync(mkcert, ['-install'], { stdio });
|
|
482
488
|
if (result.error)
|
|
483
489
|
throw result.error;
|
|
484
490
|
if (result.status !== 0) {
|
|
@@ -494,7 +500,7 @@ async function ensureCerts(config) {
|
|
|
494
500
|
rmSync(key, { force: true });
|
|
495
501
|
const names = [...new Set([config.host, 'localhost', '127.0.0.1', '::1'])];
|
|
496
502
|
const args = ['-cert-file', cert, '-key-file', key, ...names];
|
|
497
|
-
const result = spawnSync(mkcert, args, {
|
|
503
|
+
const result = spawnSync(mkcert, args, { stdio });
|
|
498
504
|
if (result.error)
|
|
499
505
|
throw result.error;
|
|
500
506
|
if (result.status !== 0) {
|
|
@@ -570,8 +576,6 @@ function mkcertInstallInstructions() {
|
|
|
570
576
|
}
|
|
571
577
|
|
|
572
578
|
function startCompose(config) {
|
|
573
|
-
const logs = join(config.cache, 'logs');
|
|
574
|
-
const output = openSync(join(logs, 'compose.log'), 'w');
|
|
575
579
|
const compose = [
|
|
576
580
|
'compose',
|
|
577
581
|
'--ansi=never',
|
|
@@ -579,6 +583,7 @@ function startCompose(config) {
|
|
|
579
583
|
`--project-name=${config.compose.name}`,
|
|
580
584
|
`--profile=${process.platform}`,
|
|
581
585
|
];
|
|
586
|
+
const dir = join(config.cache, 'logs');
|
|
582
587
|
const env = {
|
|
583
588
|
COMPOSE_MENU: 'false',
|
|
584
589
|
...(config.oauth2.public
|
|
@@ -588,12 +593,32 @@ function startCompose(config) {
|
|
|
588
593
|
[config.secrets.edgeKey]: config.edgeKey,
|
|
589
594
|
[config.secrets.cookieSecret]: randomBytes(32).toString('base64url'),
|
|
590
595
|
};
|
|
591
|
-
const opts = {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
+
const opts = { cwd: config.cache, env };
|
|
597
|
+
function validate() {
|
|
598
|
+
const args = [
|
|
599
|
+
...compose,
|
|
600
|
+
'run',
|
|
601
|
+
'--build',
|
|
602
|
+
'--quiet-build',
|
|
603
|
+
'--rm',
|
|
604
|
+
'--no-deps',
|
|
605
|
+
'nginx',
|
|
606
|
+
'nginx',
|
|
607
|
+
'-t',
|
|
608
|
+
'-q',
|
|
609
|
+
];
|
|
610
|
+
const result = spawnSync('docker', args, {
|
|
611
|
+
...opts,
|
|
612
|
+
stdio: ['ignore', 'ignore', 'inherit'],
|
|
613
|
+
});
|
|
614
|
+
if (result.error)
|
|
615
|
+
throw result.error;
|
|
616
|
+
if (result.status !== 0) {
|
|
617
|
+
throw new Error('Failed to validate NGINX configuration');
|
|
618
|
+
}
|
|
619
|
+
}
|
|
596
620
|
function up() {
|
|
621
|
+
const out = openSync(join(dir, 'compose.log'), 'w');
|
|
597
622
|
const args = [
|
|
598
623
|
...compose,
|
|
599
624
|
'up',
|
|
@@ -601,13 +626,20 @@ function startCompose(config) {
|
|
|
601
626
|
'--force-recreate',
|
|
602
627
|
'--remove-orphans',
|
|
603
628
|
];
|
|
604
|
-
return spawnSync('docker', args, opts);
|
|
629
|
+
return spawnSync('docker', args, { ...opts, stdio: ['ignore', out, out] });
|
|
605
630
|
}
|
|
606
631
|
function down() {
|
|
632
|
+
const out = openSync(join(dir, 'compose.log'), 'a');
|
|
607
633
|
const args = [...compose, 'down', '--remove-orphans'];
|
|
608
|
-
return spawnSync('docker', args, opts);
|
|
634
|
+
return spawnSync('docker', args, { ...opts, stdio: ['ignore', out, out] });
|
|
635
|
+
}
|
|
636
|
+
function follow() {
|
|
637
|
+
const out = openSync(join(dir, 'container.log'), 'w');
|
|
638
|
+
const args = [...compose, 'logs', '--follow'];
|
|
639
|
+
return spawn('docker', args, { ...opts, stdio: ['ignore', out, out] });
|
|
609
640
|
}
|
|
610
641
|
down();
|
|
642
|
+
validate();
|
|
611
643
|
const result = up();
|
|
612
644
|
if (result.error)
|
|
613
645
|
throw result.error;
|
|
@@ -615,7 +647,11 @@ function startCompose(config) {
|
|
|
615
647
|
down();
|
|
616
648
|
throw new Error('Failed to start Docker Compose');
|
|
617
649
|
}
|
|
618
|
-
|
|
650
|
+
const logs = follow();
|
|
651
|
+
return () => {
|
|
652
|
+
down();
|
|
653
|
+
logs.kill('SIGINT');
|
|
654
|
+
};
|
|
619
655
|
}
|
|
620
656
|
|
|
621
657
|
const HOSTS_FILE = '/etc/hosts';
|
|
@@ -670,12 +706,6 @@ function writeComposeConfig(config) {
|
|
|
670
706
|
}
|
|
671
707
|
function renderComposeConfig(config) {
|
|
672
708
|
const { dex, nginx, oauth2_proxy, ...services } = config.services;
|
|
673
|
-
const bridge = spawnSync('docker', [
|
|
674
|
-
'network',
|
|
675
|
-
'inspect',
|
|
676
|
-
'bridge',
|
|
677
|
-
'--format={{ (index .IPAM.Config 0).Gateway }}',
|
|
678
|
-
], { encoding: 'utf8' }).stdout.trim();
|
|
679
709
|
return stringify({
|
|
680
710
|
secrets: {
|
|
681
711
|
[config.secrets.cookieSecret]: {
|
|
@@ -711,7 +741,9 @@ function renderComposeConfig(config) {
|
|
|
711
741
|
? {
|
|
712
742
|
vite_loopback: {
|
|
713
743
|
image: DockerImages.socat.image,
|
|
714
|
-
command: `tcp-listen:${config.upstreams.vite.port},fork,bind
|
|
744
|
+
command: `tcp-listen:${config.upstreams.vite.port},fork,bind=host.docker.internal ` +
|
|
745
|
+
`tcp-connect:127.0.0.1:${config.upstreams.vite.port}`,
|
|
746
|
+
extra_hosts: ['host.docker.internal:host-gateway'],
|
|
715
747
|
network_mode: 'host',
|
|
716
748
|
profiles: ['linux'],
|
|
717
749
|
restart: 'always',
|
|
@@ -784,6 +816,7 @@ function renderDexConfig(config) {
|
|
|
784
816
|
|
|
785
817
|
const template = `
|
|
786
818
|
load_module modules/ngx_http_js_module.so;
|
|
819
|
+
include /etc/nginx/modules/*.conf;
|
|
787
820
|
|
|
788
821
|
events {}
|
|
789
822
|
|
|
@@ -792,6 +825,8 @@ http {
|
|
|
792
825
|
js_shared_dict_zone zone=edge_key:32k;
|
|
793
826
|
js_set $edge_key edge_key;
|
|
794
827
|
|
|
828
|
+
include /etc/nginx/http.d/*.conf;
|
|
829
|
+
|
|
795
830
|
# Disable IPv6 DNS lookup. Docker Desktop (com.docker.backend), doesn't
|
|
796
831
|
# support IPv6 traffic translation to host loopback.
|
|
797
832
|
resolver 127.0.0.11 ipv6=off;
|
|
@@ -809,16 +844,49 @@ http {
|
|
|
809
844
|
'' close;
|
|
810
845
|
}
|
|
811
846
|
|
|
812
|
-
# Fetch Metadata CSRF
|
|
813
|
-
map $
|
|
814
|
-
default
|
|
815
|
-
|
|
816
|
-
|
|
847
|
+
# Fetch Metadata CSRF guard for cookie auth locations.
|
|
848
|
+
map $request_method $csrf_method {
|
|
849
|
+
default unsafe;
|
|
850
|
+
GET safe;
|
|
851
|
+
HEAD safe;
|
|
852
|
+
OPTIONS safe;
|
|
853
|
+
}
|
|
854
|
+
map $http_origin $csrf_origin {
|
|
855
|
+
default invalid;
|
|
856
|
+
'' absent;
|
|
857
|
+
"<%~ it.csrf.origin %>" match;
|
|
858
|
+
}
|
|
859
|
+
map $http_referer $csrf_referer {
|
|
860
|
+
default invalid;
|
|
861
|
+
'' absent;
|
|
862
|
+
"<%~ it.csrf.referer %>" match;
|
|
817
863
|
}
|
|
818
|
-
map "$
|
|
819
|
-
default
|
|
820
|
-
~^
|
|
821
|
-
|
|
864
|
+
map "$csrf_method:$csrf_origin:$csrf_referer" $csrf_fallback {
|
|
865
|
+
default deny;
|
|
866
|
+
"~^safe:.*:.*$" allow;
|
|
867
|
+
unsafe:match:match allow;
|
|
868
|
+
unsafe:match:absent allow;
|
|
869
|
+
unsafe:absent:match allow;
|
|
870
|
+
}
|
|
871
|
+
map "$request_method:$http_sec_fetch_mode:$http_sec_fetch_dest" $csrf_doc_nav {
|
|
872
|
+
default 0;
|
|
873
|
+
GET:navigate:document 1;
|
|
874
|
+
}
|
|
875
|
+
map "$http_sec_fetch_site:$csrf_doc_nav" $csrf_fetch_metadata {
|
|
876
|
+
default fallback;
|
|
877
|
+
"~^(same-origin|none):(0|1)$" allow;
|
|
878
|
+
"~^(same-site|cross-site):1$" allow;
|
|
879
|
+
"~^(same-site|cross-site):0$" deny;
|
|
880
|
+
}
|
|
881
|
+
map "$csrf_fetch_metadata:$csrf_fallback" $csrf_reject {
|
|
882
|
+
default 1;
|
|
883
|
+
allow:deny 0;
|
|
884
|
+
allow:allow 0;
|
|
885
|
+
fallback:allow 0;
|
|
886
|
+
}
|
|
887
|
+
map "$request_method:$http_sec_fetch_mode:$http_sec_fetch_dest" $auth_error_page {
|
|
888
|
+
default @auth_401;
|
|
889
|
+
~^(GET|HEAD):navigate:document$ @auth_redirect;
|
|
822
890
|
}
|
|
823
891
|
|
|
824
892
|
<%_ for (const [name, upstream] of Object.entries(it.upstreams)) { %>
|
|
@@ -841,25 +909,20 @@ http {
|
|
|
841
909
|
ssl_certificate_key <%~ it.ssl.key %>;
|
|
842
910
|
|
|
843
911
|
access_log /var/log/nginx/access.log access_log_format;
|
|
844
|
-
set $auth_email "";
|
|
845
912
|
|
|
846
913
|
# Redirect HTTP to HTTPS.
|
|
847
914
|
error_page 497 =301 https://$http_host$request_uri;
|
|
848
915
|
|
|
916
|
+
set $auth_email "";
|
|
917
|
+
|
|
849
918
|
<%_ for (const [name, upstream] of Object.entries(it.upstreams)) { %>
|
|
850
919
|
<%_ for (const [path, location] of Object.entries(upstream.locations)) { %>
|
|
851
920
|
location <%~ path %> {
|
|
852
921
|
<%_ if (location.csrf) { %>
|
|
853
|
-
add_header Vary "Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest" always;
|
|
854
|
-
|
|
855
|
-
if ($csrf_app) {
|
|
922
|
+
add_header Vary "Sec-Fetch-Site, Sec-Fetch-Mode, Sec-Fetch-Dest, Origin, Referer" always;
|
|
923
|
+
if ($csrf_reject) {
|
|
856
924
|
return 403;
|
|
857
925
|
}
|
|
858
|
-
<%_ } else { %>
|
|
859
|
-
if ($csrf_api) {
|
|
860
|
-
return 403;
|
|
861
|
-
}
|
|
862
|
-
<%_ } %>
|
|
863
926
|
|
|
864
927
|
<%_ } %>
|
|
865
928
|
<%_ if (location.auth?.enabled) { %>
|
|
@@ -874,10 +937,7 @@ http {
|
|
|
874
937
|
# Propagate refreshed session cookie.
|
|
875
938
|
auth_request_set $auth_cookie $upstream_http_set_cookie;
|
|
876
939
|
add_header Set-Cookie $auth_cookie;
|
|
877
|
-
|
|
878
|
-
<%_ if (location.auth.redirect) { %>
|
|
879
|
-
error_page 401 =302 /oauth2/start?rd=$scheme://$http_host$request_uri;
|
|
880
|
-
<%_ } %>
|
|
940
|
+
error_page 401 = $auth_error_page;
|
|
881
941
|
<%_ } %>
|
|
882
942
|
<%_ if (name === 'vite') { %>
|
|
883
943
|
proxy_set_header <%~ it.edgeKey.header %> $edge_key;
|
|
@@ -892,11 +952,11 @@ http {
|
|
|
892
952
|
<%_ } %>
|
|
893
953
|
<%_ if (upstream.scheme === 'https') { %>
|
|
894
954
|
proxy_ssl_server_name on;
|
|
895
|
-
proxy_ssl_name
|
|
955
|
+
proxy_ssl_name <%~ upstream.host %>;
|
|
896
956
|
<%_ if (upstream.external) { %>
|
|
897
957
|
proxy_ssl_trusted_certificate /etc/ssl/certs/ca-certificates.crt;
|
|
898
|
-
proxy_ssl_verify
|
|
899
|
-
proxy_ssl_verify_depth
|
|
958
|
+
proxy_ssl_verify on;
|
|
959
|
+
proxy_ssl_verify_depth 3;
|
|
900
960
|
<%_ } %>
|
|
901
961
|
<%_ } %>
|
|
902
962
|
proxy_pass <%~ upstream.scheme %>://<%~ name %>;
|
|
@@ -904,6 +964,12 @@ http {
|
|
|
904
964
|
<%_ } %>
|
|
905
965
|
|
|
906
966
|
<%_ } %>
|
|
967
|
+
location @auth_redirect {
|
|
968
|
+
return 302 /oauth2/start?rd=$scheme://$http_host$request_uri;
|
|
969
|
+
}
|
|
970
|
+
location @auth_401 {
|
|
971
|
+
return 401;
|
|
972
|
+
}
|
|
907
973
|
}
|
|
908
974
|
}
|
|
909
975
|
`;
|
|
@@ -926,9 +992,12 @@ function writeNginxConfig(config) {
|
|
|
926
992
|
writeFileSync(edgeKeyFile, edgeKeyRender, 'utf-8');
|
|
927
993
|
}
|
|
928
994
|
function renderNginxConfig(config) {
|
|
995
|
+
const origin = `https://${config.host}:${config.port}`;
|
|
996
|
+
const referer = `~^${origin.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}([/?#]|$)`;
|
|
929
997
|
const data = {
|
|
930
998
|
host: config.host,
|
|
931
999
|
port: config.port,
|
|
1000
|
+
csrf: { origin, referer },
|
|
932
1001
|
ssl: {
|
|
933
1002
|
cert: join(config.files.certs[1], 'tls.crt'),
|
|
934
1003
|
key: join(config.files.certs[1], 'tls.key'),
|
|
@@ -943,7 +1012,7 @@ function renderNginxConfig(config) {
|
|
|
943
1012
|
...upstream,
|
|
944
1013
|
resolve: upstream.host === 'host.docker.internal'
|
|
945
1014
|
? process.platform !== 'linux'
|
|
946
|
-
: upstream.
|
|
1015
|
+
: isIP(upstream.host) === 0,
|
|
947
1016
|
},
|
|
948
1017
|
])),
|
|
949
1018
|
};
|
|
@@ -965,6 +1034,7 @@ function writeOauth2ProxyConfig(config) {
|
|
|
965
1034
|
function renderOauth2ProxyConfig(config) {
|
|
966
1035
|
const data = {
|
|
967
1036
|
http_address: `127.0.0.1:${config.upstreams.oauth2_proxy.port}`,
|
|
1037
|
+
metrics_address: '0.0.0.0:4181',
|
|
968
1038
|
provider: 'oidc',
|
|
969
1039
|
oidc_issuer_url: config.idp.oidc.issuer,
|
|
970
1040
|
...(config.idp.oidc.algs === undefined
|
|
@@ -1078,7 +1148,7 @@ function visage(options = {}) {
|
|
|
1078
1148
|
server: {
|
|
1079
1149
|
// Configure Vite to only allow traffic from the intended host.
|
|
1080
1150
|
allowedHosts: [resolvedOptions.host],
|
|
1081
|
-
|
|
1151
|
+
ws: {
|
|
1082
1152
|
protocol: 'wss',
|
|
1083
1153
|
host: resolvedOptions.host,
|
|
1084
1154
|
clientPort: resolvedOptions.port,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/render/compose.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compose.d.ts","sourceRoot":"","sources":["../../src/render/compose.ts"],"names":[],"mappings":"AAKA,OAAO,EAAgB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAE5D,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAI7D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/render/nginx.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"nginx.d.ts","sourceRoot":"","sources":["../../src/render/nginx.ts"],"names":[],"mappings":"AAKA,OAAO,EAAuB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AA6KnE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CAQ3D"}
|
package/dist/types.d.ts
CHANGED
|
@@ -256,6 +256,10 @@ export type VisageOAuth2Client = {
|
|
|
256
256
|
* Subset of a Docker Compose service definition managed by Visage.
|
|
257
257
|
*/
|
|
258
258
|
export type VisageService = {
|
|
259
|
+
/**
|
|
260
|
+
* Docker build context for the service.
|
|
261
|
+
*/
|
|
262
|
+
readonly build?: string;
|
|
259
263
|
/**
|
|
260
264
|
* Container image reference used for the service. Required for additional
|
|
261
265
|
* services; defaults to the managed image when overriding `nginx` or
|
|
@@ -280,6 +284,11 @@ export type VisageService = {
|
|
|
280
284
|
* Docker network mode rendered into the Compose service.
|
|
281
285
|
*/
|
|
282
286
|
readonly network_mode?: string;
|
|
287
|
+
/**
|
|
288
|
+
* Compose image pull policy.
|
|
289
|
+
* @defaultValue `'missing'`
|
|
290
|
+
*/
|
|
291
|
+
readonly pull_policy?: 'always' | 'build' | 'missing' | 'never';
|
|
283
292
|
/**
|
|
284
293
|
* Additional host-to-IP mappings rendered into the Compose service.
|
|
285
294
|
*/
|
|
@@ -321,6 +330,13 @@ export type VisageUpstream = {
|
|
|
321
330
|
* @defaultValue `80`, or `443` when {@link VisageUpstream.scheme} is `'https'`.
|
|
322
331
|
*/
|
|
323
332
|
readonly port?: number;
|
|
333
|
+
/**
|
|
334
|
+
* Request headers to apply to every location for this upstream. Per-location
|
|
335
|
+
* headers override matching values from this map.
|
|
336
|
+
*/
|
|
337
|
+
readonly headers?: {
|
|
338
|
+
readonly [key: string]: string;
|
|
339
|
+
};
|
|
324
340
|
/**
|
|
325
341
|
* Path-location policies for this upstream, keyed by NGINX location path.
|
|
326
342
|
*
|
|
@@ -344,12 +360,6 @@ export type VisageProxyPolicy = {
|
|
|
344
360
|
* @defaultValue `true`
|
|
345
361
|
*/
|
|
346
362
|
readonly enabled?: boolean;
|
|
347
|
-
/**
|
|
348
|
-
* Whether unauthenticated browser requests should redirect to sign-in.
|
|
349
|
-
*
|
|
350
|
-
* @defaultValue `false`
|
|
351
|
-
*/
|
|
352
|
-
readonly redirect?: boolean;
|
|
353
363
|
/**
|
|
354
364
|
* Token forwarding behavior for the upstream `Authorization` header. Set
|
|
355
365
|
* to `false` to omit a bearer token. Set to `true` to forward the
|
|
@@ -367,10 +377,20 @@ export type VisageProxyPolicy = {
|
|
|
367
377
|
* locations. Set this to `false` when an upstream handles CSRF itself or
|
|
368
378
|
* intentionally accepts cross-site browser requests.
|
|
369
379
|
*
|
|
370
|
-
* @defaultValue `
|
|
371
|
-
*
|
|
380
|
+
* @defaultValue `true` for authenticated locations; `false` for
|
|
381
|
+
* unauthenticated locations.
|
|
382
|
+
*/
|
|
383
|
+
readonly csrf?: boolean;
|
|
384
|
+
/**
|
|
385
|
+
* Whether to add WebSocket proxy support for this location.
|
|
386
|
+
*
|
|
387
|
+
* When enabled, Visage adds `Connection` and `Upgrade` proxy headers plus
|
|
388
|
+
* `proxy_http_version` and `proxy_read_timeout` directives unless the
|
|
389
|
+
* location explicitly overrides them.
|
|
390
|
+
*
|
|
391
|
+
* @defaultValue `false`
|
|
372
392
|
*/
|
|
373
|
-
readonly
|
|
393
|
+
readonly ws?: boolean;
|
|
374
394
|
/**
|
|
375
395
|
* Request headers to set when proxying to the upstream. Values may include
|
|
376
396
|
* NGINX variables. These are merged with Visage's default proxy headers:
|
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;;;OAGG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,GAAG,CAAC,EAAE,gBAAgB,GAAG,wBAAwB,CAAC;IAC3D;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IAClD;;OAEG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;CACrD,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;OAOG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;;;OAQG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,eAAe,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,aAAa,EAAE,CAAC;CAC3C,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG;IAC5B;;OAEG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;OAEG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B;;OAEG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE;QACvB;;WAEG;QACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;QACpC;;WAEG;QACH,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;QACnC;;WAEG;QACH,QAAQ,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC;QACnC;;WAEG;QACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;KACjC,CAAC;CACH,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;OAEG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG;IACrC;;;OAGG;IACH,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB;;;;OAIG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC;;;;;OAKG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CACxC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;;;OAOG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC;;;;OAIG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC3C,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC;IAC3D;;OAEG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC;;OAEG;IACH,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B;;OAEG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACzC;;;OAGG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,GAAG,IAAI,GAAG,YAAY,GAAG,gBAAgB,CAAC;IACrE;;OAEG;IACH,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC;;;OAGG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;CACpC,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACnC;;;;OAIG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,GAAG,iBAAiB,CAAA;KAAE,CAAC;CACrE,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B;;OAEG;IACH,QAAQ,CAAC,IAAI,CAAC,EAAE;QACd;;;;WAIG;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAC3B
|
|
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.5-rc.
|
|
3
|
+
"version": "0.0.5-rc.21",
|
|
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",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"devDependencies": {
|
|
62
62
|
"@playwright/test": "^1.61.1",
|
|
63
63
|
"@rollup/plugin-typescript": "^12.3.0",
|
|
64
|
-
"@types/node": "^26.
|
|
64
|
+
"@types/node": "^26.1.1",
|
|
65
65
|
"rollup": "^4.62.2",
|
|
66
66
|
"tslib": "^2.8.1",
|
|
67
|
-
"tsx": "^4.
|
|
67
|
+
"tsx": "^4.23.0",
|
|
68
68
|
"typescript": "^6.0.3",
|
|
69
|
-
"vite": "^8.1.
|
|
69
|
+
"vite": "^8.1.4"
|
|
70
70
|
}
|
|
71
71
|
}
|