@lamalibre/create-lamaste 4.6.0 → 4.7.0
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/package.json +2 -2
- package/scripts/bundle-vendor.js +20 -3
- package/scripts/lamaste-priv +22 -3
- package/scripts/pin-release.js +98 -0
- package/src/index.js +8 -1
- package/src/lib/env.js +19 -0
- package/src/lib/service-config.js +7 -0
- package/src/tasks/redeploy.js +8 -0
- package/vendor/docs/00-introduction/how-it-works.md +2 -2
- package/vendor/docs/00-introduction/quickstart.md +5 -5
- package/vendor/docs/00-introduction/what-is-lamaste.md +5 -5
- package/vendor/docs/01-concepts/authentication.md +6 -2
- package/vendor/docs/01-concepts/authorization.md +4 -0
- package/vendor/docs/01-concepts/certificates.md +3 -3
- package/vendor/docs/01-concepts/dns-and-domains.md +9 -0
- package/vendor/docs/01-concepts/mtls.md +2 -2
- package/vendor/docs/01-concepts/security-model.md +28 -3
- package/vendor/docs/01-concepts/tickets.md +2 -2
- package/vendor/docs/01-concepts/tunneling.md +4 -4
- package/vendor/docs/02-guides/agent-setup.md +5 -5
- package/vendor/docs/02-guides/certificate-management.md +2 -2
- package/vendor/docs/02-guides/cloud-provisioning.md +3 -3
- package/vendor/docs/02-guides/desktop-app-setup.md +10 -10
- package/vendor/docs/02-guides/installation.md +3 -3
- package/vendor/docs/02-guides/managing-users.md +5 -11
- package/vendor/docs/02-guides/onboarding.md +2 -2
- package/vendor/docs/02-guides/second-domain.md +82 -0
- package/vendor/docs/02-guides/standalone-plugin-with-tickets.md +2 -2
- package/vendor/docs/03-architecture/installer-flow.md +2 -2
- package/vendor/docs/03-architecture/installer.md +4 -4
- package/vendor/docs/03-architecture/management-flow.md +1 -1
- package/vendor/docs/03-architecture/nginx-configuration.md +15 -5
- package/vendor/docs/03-architecture/overview.md +5 -5
- package/vendor/docs/03-architecture/panel-client.md +6 -6
- package/vendor/docs/03-architecture/panel-server.md +2 -2
- package/vendor/docs/03-architecture/state-management.md +3 -3
- package/vendor/docs/03-architecture/system-overview.md +1 -1
- package/vendor/docs/04-api-reference/agent-hosted-plugins.md +17 -13
- package/vendor/docs/04-api-reference/app-host.md +3 -3
- package/vendor/docs/04-api-reference/domains.md +192 -0
- package/vendor/docs/04-api-reference/gatekeeper.md +35 -7
- package/vendor/docs/04-api-reference/lifecycle-hooks.md +4 -4
- package/vendor/docs/04-api-reference/onboarding.md +1 -1
- package/vendor/docs/04-api-reference/overview.md +9 -0
- package/vendor/docs/04-api-reference/registry-and-oidc.md +26 -13
- package/vendor/docs/04-api-reference/sites.md +5 -0
- package/vendor/docs/04-api-reference/tunnels.md +15 -10
- package/vendor/docs/04-api-reference/users.md +41 -29
- package/vendor/docs/05-operations/backup-and-restore.md +1 -1
- package/vendor/docs/05-operations/uninstalling.md +1 -1
- package/vendor/docs/05-operations/upgrades.md +6 -6
- package/vendor/docs/06-reference/config-files.md +1 -1
- package/vendor/docs/06-reference/glossary.md +3 -3
- package/vendor/docs/06-reference/installer-flags.md +13 -13
- package/vendor/docs/06-reference/ports-and-services.md +1 -1
- package/vendor/docs/06-reference/troubleshooting.md +8 -8
- package/vendor/docs/_index.json +105 -19
- package/vendor/docs/external-members-design.md +816 -0
- package/vendor/docs/gatekeeper-design.md +8 -8
- package/vendor/docs/identity-directory-design.md +3 -3
- package/vendor/docs/multi-domain-relay-design.md +836 -0
- package/vendor/docs/package.json +1 -1
- package/vendor/docs/todo/lib-cli-desktop-refactor.md +27 -27
- package/vendor/gatekeeper/dist/cli/index.js +0 -0
- package/vendor/gatekeeper/dist/lib/grants.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/grants.js +20 -13
- package/vendor/gatekeeper/dist/lib/grants.js.map +1 -1
- package/vendor/gatekeeper/dist/lib/migrations/gatekeeper/0004_unconsume_access_grants.sql +8 -0
- package/vendor/gatekeeper/dist/lib/secret.d.ts +6 -0
- package/vendor/gatekeeper/dist/lib/secret.d.ts.map +1 -0
- package/vendor/gatekeeper/dist/lib/secret.js +12 -0
- package/vendor/gatekeeper/dist/lib/secret.js.map +1 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts +20 -0
- package/vendor/gatekeeper/dist/lib/templates.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/lib/templates.js +80 -14
- package/vendor/gatekeeper/dist/lib/templates.js.map +1 -1
- package/vendor/gatekeeper/dist/server/index.d.ts +5 -1
- package/vendor/gatekeeper/dist/server/index.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/index.js +28 -2
- package/vendor/gatekeeper/dist/server/index.js.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/authz.js +225 -36
- package/vendor/gatekeeper/dist/server/routes/authz.js.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/diagnostic.d.ts.map +1 -1
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js +5 -2
- package/vendor/gatekeeper/dist/server/routes/diagnostic.js.map +1 -1
- package/vendor/gatekeeper/package.json +2 -2
- package/vendor/server/bin/lamaste-server.js +7 -0
- package/vendor/server/package.json +2 -2
- package/vendor/server/src/commands/domains.js +214 -0
- package/vendor/server/src/commands/plugin-identity.js +2 -16
- package/vendor/server/src/commands/plugins.js +112 -8
- package/vendor/server/src/commands/registry-credential.js +10 -3
- package/vendor/server/src/commands/sites.js +3 -0
- package/vendor/server/src/commands/status.js +19 -0
- package/vendor/server/src/commands/tunnels.js +4 -1
- package/vendor/server/src/commands/users.js +8 -19
- package/vendor/server/src/domains.js +92 -0
- package/vendor/server/src/fail.js +21 -0
- package/vendor/server/src/oidc-client-grants.js +63 -0
- package/vendor/server/src/panel-api.js +15 -0
- package/vendor/server-ui/dist/assets/index-B8Tv_ocF.js +84 -0
- package/vendor/server-ui/dist/assets/{index-BZwQ_aQc.css → index-Cb-ADsbB.css} +1 -1
- package/vendor/server-ui/dist/index.html +2 -2
- package/vendor/serverd/package.json +2 -2
- package/vendor/serverd/src/index.js +42 -16
- package/vendor/serverd/src/lib/app-error.js +24 -0
- package/vendor/serverd/src/lib/audience.js +12 -3
- package/vendor/serverd/src/lib/authelia.js +341 -35
- package/vendor/serverd/src/lib/directory.js +67 -52
- package/vendor/serverd/src/lib/domains.js +1792 -0
- package/vendor/serverd/src/lib/gatekeeper-client.js +20 -4
- package/vendor/serverd/src/lib/identity-sync.js +35 -0
- package/vendor/serverd/src/lib/migrations/state/0016_domains.sql +53 -0
- package/vendor/serverd/src/lib/migrations/state/0017_membership_kind.sql +15 -0
- package/vendor/serverd/src/lib/migrations/state/0018_domain_group_keys.sql +23 -0
- package/vendor/serverd/src/lib/nginx.js +318 -140
- package/vendor/serverd/src/lib/owned-groups.js +326 -0
- package/vendor/serverd/src/lib/plugin-domain.js +86 -0
- package/vendor/serverd/src/lib/plugin-lifecycle.js +1 -0
- package/vendor/serverd/src/lib/plugin-oidc.js +144 -42
- package/vendor/serverd/src/lib/plugins.js +45 -5
- package/vendor/serverd/src/lib/registry-credential.js +39 -6
- package/vendor/serverd/src/lib/services.js +9 -1
- package/vendor/serverd/src/lib/state.js +11 -0
- package/vendor/serverd/src/lib/tunnel-deps.js +2 -4
- package/vendor/serverd/src/lib/user-surface.js +29 -4
- package/vendor/serverd/src/lib/users-lock.js +23 -0
- package/vendor/serverd/src/lib/vhost-reconcile.js +149 -41
- package/vendor/serverd/src/lib/web-surface.js +49 -32
- package/vendor/serverd/src/middleware/user-access-session.js +11 -4
- package/vendor/serverd/src/routes/invite.js +15 -5
- package/vendor/serverd/src/routes/management/domains.js +154 -0
- package/vendor/serverd/src/routes/management/gatekeeper-proxy.js +44 -8
- package/vendor/serverd/src/routes/management/identity.js +21 -7
- package/vendor/serverd/src/routes/management/invitations.js +33 -4
- package/vendor/serverd/src/routes/management/plugins.js +4 -2
- package/vendor/serverd/src/routes/management/registry-credential.js +86 -57
- package/vendor/serverd/src/routes/management/sites.js +50 -11
- package/vendor/serverd/src/routes/management/tunnels.js +29 -5
- package/vendor/serverd/src/routes/management/users.js +184 -64
- package/vendor/serverd/src/routes/management.js +2 -0
- package/vendor/serverd/src/routes/onboarding/dns.js +3 -17
- package/vendor/serverd/src/routes/onboarding/provision.js +22 -13
- package/vendor/serverd/src/routes/user-access.js +13 -1
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0001_groups.sql +0 -7
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0002_access_grants.sql +0 -14
- package/vendor/gatekeeper/dist/lib/migrations/migrations/gatekeeper/0003_access_request_log.sql +0 -9
- package/vendor/server-ui/dist/assets/index-BvEfCZYS.js +0 -84
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The relay's domains as `lamaste-server domains` prints them — pure
|
|
3
|
+
* helpers, exported for tests (the command is src/commands/domains.js).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { terminalText } from './plugin-settings.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* One row per domain: name, state, members, what uses it — as terminal text.
|
|
10
|
+
*
|
|
11
|
+
* @param {Array<Record<string, any>>} domains as `GET /api/domains` lists them
|
|
12
|
+
*/
|
|
13
|
+
export function domainRows(domains) {
|
|
14
|
+
return domains.map((d) => ({
|
|
15
|
+
name: terminalText(d.name),
|
|
16
|
+
state: d.status === 'active' ? (d.primary ? 'primary' : 'active') : 'pending',
|
|
17
|
+
members: Number.isInteger(d.members) ? d.members : 0,
|
|
18
|
+
externalMembers: Number.isInteger(d.externalMembers) ? d.externalMembers : 0,
|
|
19
|
+
usedBy: usageText(d.usedBy),
|
|
20
|
+
}));
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/** What uses a domain, in one line (empty when nothing does). */
|
|
24
|
+
export function usageText(usedBy) {
|
|
25
|
+
if (!usedBy) return '';
|
|
26
|
+
const parts = [];
|
|
27
|
+
const count = (label, items) => {
|
|
28
|
+
if (Array.isArray(items) && items.length > 0) parts.push(`${items.length} ${label}`);
|
|
29
|
+
};
|
|
30
|
+
count('tunnel(s)', usedBy.tunnels);
|
|
31
|
+
count('site(s)', usedBy.sites);
|
|
32
|
+
count('plugin(s)', usedBy.plugins);
|
|
33
|
+
if (usedBy.registry) parts.push('the registry credential');
|
|
34
|
+
return parts.join(', ');
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** `/api/domains/<name><rest>`. */
|
|
38
|
+
export function domainPath(name, rest = '') {
|
|
39
|
+
return `/api/domains/${encodeURIComponent(name)}${rest}`;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* A user's memberships in one line — `a.example, b.example (external)` —
|
|
44
|
+
* as terminal text; `—` for none. A bare name (an older panel's answer) is
|
|
45
|
+
* a member.
|
|
46
|
+
*
|
|
47
|
+
* @param {ReadonlyArray<string | { name: string, kind?: string }> | undefined} domains
|
|
48
|
+
*/
|
|
49
|
+
export function membershipsText(domains) {
|
|
50
|
+
const parts = (domains ?? []).flatMap((d) => {
|
|
51
|
+
const name = typeof d === 'string' ? d : d?.name;
|
|
52
|
+
if (typeof name !== 'string') return [];
|
|
53
|
+
return [terminalText(d?.kind === 'external' ? `${name} (external)` : name)];
|
|
54
|
+
});
|
|
55
|
+
return parts.length > 0 ? parts.join(', ') : '—';
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Whether any of `domains` is an external membership. */
|
|
59
|
+
export function isExternalAnywhere(domains) {
|
|
60
|
+
return (domains ?? []).some((d) => d?.kind === 'external');
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* What `domains members <domain> <action> <user> …` asks the panel, or
|
|
65
|
+
* null for a command line it does not take:
|
|
66
|
+
*
|
|
67
|
+
* - `add <user> [--external]` — a member (an external one with the flag);
|
|
68
|
+
* - `kind <user> member|external` — change the kind of a membership;
|
|
69
|
+
* - `remove <user>` — end it.
|
|
70
|
+
*
|
|
71
|
+
* `user` is a directory id or a username.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} domain
|
|
74
|
+
* @param {string[]} rest what follows `members <domain>`
|
|
75
|
+
* @returns {{ method: 'PUT' | 'DELETE', path: string, body: object | null, user: string, kind: 'member' | 'external' | null } | null}
|
|
76
|
+
*/
|
|
77
|
+
export function memberRequest(domain, rest) {
|
|
78
|
+
const [action, user, ...more] = rest;
|
|
79
|
+
if (!user) return null;
|
|
80
|
+
const path = domainPath(domain, `/members/${encodeURIComponent(user)}`);
|
|
81
|
+
if (action === 'remove' && more.length === 0) {
|
|
82
|
+
return { method: 'DELETE', path, body: null, user, kind: null };
|
|
83
|
+
}
|
|
84
|
+
if (action === 'add' && more.every((a) => a === '--external')) {
|
|
85
|
+
const kind = more.length > 0 ? 'external' : 'member';
|
|
86
|
+
return { method: 'PUT', path, body: { kind }, user, kind };
|
|
87
|
+
}
|
|
88
|
+
if (action === 'kind' && more.length === 1 && (more[0] === 'member' || more[0] === 'external')) {
|
|
89
|
+
return { method: 'PUT', path, body: { kind: more[0] }, user, kind: more[0] };
|
|
90
|
+
}
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exit a command with a usage error or a panel refusal — as text, or as an
|
|
3
|
+
* NDJSON error carrying the refusal's `code` (e.g. `last_admin`,
|
|
4
|
+
* `domain_in_use`). The message is printed only as terminal text.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import chalk from 'chalk';
|
|
8
|
+
import { emitError } from './ndjson.js';
|
|
9
|
+
import { terminalText } from './plugin-settings.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {string} message
|
|
13
|
+
* @param {boolean} json
|
|
14
|
+
* @param {{ code?: string }} [err]
|
|
15
|
+
* @returns {never}
|
|
16
|
+
*/
|
|
17
|
+
export function fail(message, json, err = {}) {
|
|
18
|
+
if (json) emitError(message, false, typeof err.code === 'string' ? { code: err.code } : {});
|
|
19
|
+
else console.error(`\n ${chalk.red(terminalText(message))}\n`);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Grants on a plugin's user-facing OIDC clients as `lamaste-server plugins
|
|
3
|
+
* oidc-clients` takes and prints them — pure helpers, exported for tests
|
|
4
|
+
* (the command is src/commands/plugins.js).
|
|
5
|
+
*
|
|
6
|
+
* A grant is a Gatekeeper grant with `resourceType: 'oidc-client'` and the
|
|
7
|
+
* client id as `resourceId`; members of the plugin's domain sign in without
|
|
8
|
+
* one, an external member only with one (to them or a Lamaste group they
|
|
9
|
+
* belong to).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { terminalText } from './plugin-settings.js';
|
|
13
|
+
|
|
14
|
+
/** The Gatekeeper resource type of a grant on an OIDC client. */
|
|
15
|
+
export const OIDC_CLIENT_RESOURCE = 'oidc-client';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The principal `--user <username>` or `--group <name>` names — exactly one
|
|
19
|
+
* of them — or null.
|
|
20
|
+
*
|
|
21
|
+
* @param {string[]} args
|
|
22
|
+
* @returns {{ principalType: 'user' | 'group', principalId: string } | null}
|
|
23
|
+
*/
|
|
24
|
+
export function parsePrincipal(args) {
|
|
25
|
+
if (args.length !== 2) return null;
|
|
26
|
+
const [flag, id] = args;
|
|
27
|
+
if (!id || id.startsWith('--')) return null;
|
|
28
|
+
if (flag === '--user') return { principalType: 'user', principalId: id };
|
|
29
|
+
if (flag === '--group') return { principalType: 'group', principalId: id };
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/** A grant's principal in words: the username, or `group:<name>`. */
|
|
34
|
+
export function principalText(grant) {
|
|
35
|
+
return terminalText(
|
|
36
|
+
grant.principalType === 'group' ? `group:${grant.principalId}` : grant.principalId,
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Every grant on `clientId` that names `principal`, among the clients
|
|
42
|
+
* `GET /api/plugins/:name/oidc-clients` lists — Gatekeeper may hold more
|
|
43
|
+
* than one (grants differing only in their context), and revoking means
|
|
44
|
+
* revoking them all — or why there is none to revoke: `no_client` (not a
|
|
45
|
+
* user-facing client of the plugin), `unreadable` (Gatekeeper could not be
|
|
46
|
+
* read), `no_grant`.
|
|
47
|
+
*
|
|
48
|
+
* @param {ReadonlyArray<Record<string, any>>} clients
|
|
49
|
+
* @param {string} clientId
|
|
50
|
+
* @param {{ principalType: string, principalId: string }} principal
|
|
51
|
+
* @returns {{ grantIds: string[] } | { error: 'no_client' | 'unreadable' | 'no_grant' }}
|
|
52
|
+
*/
|
|
53
|
+
export function findClientGrants(clients, clientId, principal) {
|
|
54
|
+
const client = clients.find((c) => c.id === clientId && c.userFacing);
|
|
55
|
+
if (!client) return { error: 'no_client' };
|
|
56
|
+
if (!Array.isArray(client.grants)) return { error: 'unreadable' };
|
|
57
|
+
const grantIds = client.grants
|
|
58
|
+
.filter(
|
|
59
|
+
(g) => g.principalType === principal.principalType && g.principalId === principal.principalId,
|
|
60
|
+
)
|
|
61
|
+
.map((g) => g.grantId);
|
|
62
|
+
return grantIds.length > 0 ? { grantIds } : { error: 'no_grant' };
|
|
63
|
+
}
|
|
@@ -129,6 +129,20 @@ export async function withCurlConfig(content, fn) {
|
|
|
129
129
|
* @param {{ identity: { certPath: string, address: string, port: number }, method: string, path: string, body?: Record<string, unknown> | null, p12Path: string, configPath: string }} request
|
|
130
130
|
* @returns {{ args: string[], input: string | undefined }}
|
|
131
131
|
*/
|
|
132
|
+
/**
|
|
133
|
+
* Refuse a request path with a `.` or `..` segment: curl and `fetch`
|
|
134
|
+
* resolve them (`/api/domains/../activate` → `/api/activate`), so a value
|
|
135
|
+
* put into a path — a domain, a user, a plugin — could name another route.
|
|
136
|
+
* Every path the client sends passes here; values are percent-encoded as
|
|
137
|
+
* usual where the path is built.
|
|
138
|
+
*/
|
|
139
|
+
export function assertPanelPath(path) {
|
|
140
|
+
const route = String(path).split(/[?#]/, 1)[0];
|
|
141
|
+
if (route.split('/').some((segment) => segment === '.' || segment === '..')) {
|
|
142
|
+
throw new Error('A panel request path may not have a "." or ".." segment');
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
|
|
132
146
|
export function buildPanelCurlRequest({
|
|
133
147
|
identity,
|
|
134
148
|
method,
|
|
@@ -137,6 +151,7 @@ export function buildPanelCurlRequest({
|
|
|
137
151
|
p12Path,
|
|
138
152
|
configPath,
|
|
139
153
|
}) {
|
|
154
|
+
assertPanelPath(path);
|
|
140
155
|
const { certPath, address, port } = identity;
|
|
141
156
|
const args = [
|
|
142
157
|
'-q', // No .curlrc — it must be the first argument
|