@axium/server 0.2.2 → 0.3.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/dist/cli.js +29 -27
- package/dist/config.d.ts +30 -30
- package/dist/config.js +2 -2
- package/dist/database.d.ts +2 -7
- package/dist/database.js +2 -8
- package/dist/io.d.ts +38 -0
- package/dist/io.js +93 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,24 +1,27 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Option, program } from 'commander';
|
|
2
|
+
import { Argument, Option, program } from 'commander';
|
|
3
3
|
import { styleText } from 'node:util';
|
|
4
|
-
import { getByString, isJSON,
|
|
4
|
+
import { getByString, isJSON, setByString } from 'utilium';
|
|
5
5
|
import $pkg from '../package.json' with { type: 'json' };
|
|
6
6
|
import * as config from './config.js';
|
|
7
7
|
import * as db from './database.js';
|
|
8
|
-
import { exit, output } from './io.js';
|
|
8
|
+
import { _portActions, _portMethods, exit, output, restrictedPorts } from './io.js';
|
|
9
9
|
program
|
|
10
10
|
.version($pkg.version)
|
|
11
11
|
.name('axium')
|
|
12
12
|
.description('Axium server CLI')
|
|
13
13
|
.configureHelp({ showGlobalOptions: true })
|
|
14
|
-
.option('
|
|
14
|
+
.option('--debug', 'override debug mode')
|
|
15
|
+
.option('--no-debug', 'override debug mode')
|
|
15
16
|
.option('-c, --config <path>', 'path to the config file');
|
|
16
|
-
program.on('option:debug', () => config.set(
|
|
17
|
+
program.on('option:debug', () => config.set({ debug: true }));
|
|
17
18
|
program.on('option:config', () => config.load(program.opts().config));
|
|
18
19
|
program.hook('preAction', function (_, action) {
|
|
19
20
|
config.loadDefaults();
|
|
20
21
|
const opt = action.optsWithGlobals();
|
|
21
22
|
opt.force && output.warn('--force: Protections disabled.');
|
|
23
|
+
if (opt.debug === false)
|
|
24
|
+
config.set({ debug: false });
|
|
22
25
|
});
|
|
23
26
|
// Options shared by multiple (sub)commands
|
|
24
27
|
const opts = {
|
|
@@ -36,30 +39,13 @@ const axiumDB = program
|
|
|
36
39
|
.description('manage the database')
|
|
37
40
|
.option('-t, --timeout <ms>', 'how long to wait for commands to complete.', '1000')
|
|
38
41
|
.addOption(opts.host);
|
|
39
|
-
function db_output(state, message = '') {
|
|
40
|
-
switch (state) {
|
|
41
|
-
case 'start':
|
|
42
|
-
process.stdout.write(message + '... ');
|
|
43
|
-
break;
|
|
44
|
-
case 'log':
|
|
45
|
-
case 'warn':
|
|
46
|
-
process.stdout.write(styleText('yellow', message));
|
|
47
|
-
break;
|
|
48
|
-
case 'error':
|
|
49
|
-
process.stdout.write(styleText('red', message));
|
|
50
|
-
break;
|
|
51
|
-
case 'done':
|
|
52
|
-
console.log('done.');
|
|
53
|
-
break;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
42
|
axiumDB
|
|
57
43
|
.command('init')
|
|
58
44
|
.description('initialize the database')
|
|
59
45
|
.addOption(opts.force)
|
|
60
46
|
.option('-s, --skip', 'Skip existing database and/or user')
|
|
61
47
|
.action(async (opt) => {
|
|
62
|
-
await db.init(
|
|
48
|
+
await db.init(opt).catch((e) => {
|
|
63
49
|
if (typeof e == 'number')
|
|
64
50
|
process.exit(e);
|
|
65
51
|
else
|
|
@@ -95,7 +81,7 @@ axiumDB
|
|
|
95
81
|
output.warn(`Database has existing ${key}. Use --force if you really want to drop the database.`);
|
|
96
82
|
process.exit(2);
|
|
97
83
|
}
|
|
98
|
-
await db.uninstall(
|
|
84
|
+
await db.uninstall(opt).catch(exit);
|
|
99
85
|
await db.database.destroy();
|
|
100
86
|
});
|
|
101
87
|
axiumDB
|
|
@@ -111,12 +97,11 @@ axiumDB
|
|
|
111
97
|
output.warn(`Database has existing ${key}. Use --force if you really want to wipe the database.`);
|
|
112
98
|
process.exit(2);
|
|
113
99
|
}
|
|
114
|
-
await db.wipe(
|
|
100
|
+
await db.wipe(opt).catch(exit);
|
|
115
101
|
await db.database.destroy();
|
|
116
102
|
});
|
|
117
103
|
const axiumConfig = program
|
|
118
104
|
.command('config')
|
|
119
|
-
.alias('conf')
|
|
120
105
|
.description('manage the configuration')
|
|
121
106
|
.option('-j, --json', 'values are JSON encoded')
|
|
122
107
|
.option('-g, --global', 'apply to the global config');
|
|
@@ -176,17 +161,34 @@ program
|
|
|
176
161
|
await db.database.destroy();
|
|
177
162
|
console.log('Credentials authentication:', config.auth.credentials ? styleText('yellow', 'enabled') : 'disabled');
|
|
178
163
|
});
|
|
164
|
+
program
|
|
165
|
+
.command('ports')
|
|
166
|
+
.description('Enable or disable use of restricted ports (e.g. 443)')
|
|
167
|
+
.addArgument(new Argument('<action>', 'The action to take').choices(_portActions))
|
|
168
|
+
.addOption(new Option('-m, --method <method>', 'the method to use').choices(_portMethods).default('node-cap'))
|
|
169
|
+
.action((action, opt) => {
|
|
170
|
+
try {
|
|
171
|
+
restrictedPorts({ ...opt, action });
|
|
172
|
+
}
|
|
173
|
+
catch (e) {
|
|
174
|
+
if (typeof e == 'number')
|
|
175
|
+
process.exit(e);
|
|
176
|
+
else
|
|
177
|
+
exit(e);
|
|
178
|
+
}
|
|
179
|
+
});
|
|
179
180
|
program
|
|
180
181
|
.command('init')
|
|
181
182
|
.description('Install Axium server')
|
|
182
183
|
.addOption(opts.force)
|
|
183
184
|
.addOption(opts.host)
|
|
184
185
|
.action(async (opt) => {
|
|
185
|
-
await db.init({ ...opt, skip: opt.dbSkip
|
|
186
|
+
await db.init({ ...opt, skip: opt.dbSkip }).catch((e) => {
|
|
186
187
|
if (typeof e == 'number')
|
|
187
188
|
process.exit(e);
|
|
188
189
|
else
|
|
189
190
|
exit(e);
|
|
190
191
|
});
|
|
192
|
+
restrictedPorts({ method: 'node-cap', action: 'enable' });
|
|
191
193
|
});
|
|
192
194
|
program.parse();
|
package/dist/config.d.ts
CHANGED
|
@@ -43,10 +43,10 @@ export declare const Log: z.ZodObject<{
|
|
|
43
43
|
level: z.ZodEnum<["error", "warn", "notice", "info", "debug"]>;
|
|
44
44
|
console: z.ZodBoolean;
|
|
45
45
|
}, "strip", z.ZodTypeAny, {
|
|
46
|
-
level: "
|
|
46
|
+
level: "warn" | "error" | "debug" | "notice" | "info";
|
|
47
47
|
console: boolean;
|
|
48
48
|
}, {
|
|
49
|
-
level: "
|
|
49
|
+
level: "warn" | "error" | "debug" | "notice" | "info";
|
|
50
50
|
console: boolean;
|
|
51
51
|
}>;
|
|
52
52
|
export type Log = z.infer<typeof Log>;
|
|
@@ -67,13 +67,13 @@ export declare const Config: z.ZodObject<{
|
|
|
67
67
|
secret: z.ZodOptional<z.ZodString>;
|
|
68
68
|
secure_cookies: z.ZodOptional<z.ZodBoolean>;
|
|
69
69
|
}, "strip", z.ZodTypeAny, {
|
|
70
|
-
credentials?: boolean | undefined;
|
|
71
70
|
debug?: boolean | undefined;
|
|
71
|
+
credentials?: boolean | undefined;
|
|
72
72
|
secret?: string | undefined;
|
|
73
73
|
secure_cookies?: boolean | undefined;
|
|
74
74
|
}, {
|
|
75
|
-
credentials?: boolean | undefined;
|
|
76
75
|
debug?: boolean | undefined;
|
|
76
|
+
credentials?: boolean | undefined;
|
|
77
77
|
secret?: string | undefined;
|
|
78
78
|
secure_cookies?: boolean | undefined;
|
|
79
79
|
}>;
|
|
@@ -101,10 +101,10 @@ export declare const Config: z.ZodObject<{
|
|
|
101
101
|
level: z.ZodOptional<z.ZodEnum<["error", "warn", "notice", "info", "debug"]>>;
|
|
102
102
|
console: z.ZodOptional<z.ZodBoolean>;
|
|
103
103
|
}, "strip", z.ZodTypeAny, {
|
|
104
|
-
level?: "
|
|
104
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
105
105
|
console?: boolean | undefined;
|
|
106
106
|
}, {
|
|
107
|
-
level?: "
|
|
107
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
108
108
|
console?: boolean | undefined;
|
|
109
109
|
}>;
|
|
110
110
|
web: z.ZodObject<{
|
|
@@ -115,10 +115,14 @@ export declare const Config: z.ZodObject<{
|
|
|
115
115
|
prefix?: string | undefined;
|
|
116
116
|
}>;
|
|
117
117
|
}, "strip", z.ZodTypeAny, {
|
|
118
|
+
log: {
|
|
119
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
120
|
+
console?: boolean | undefined;
|
|
121
|
+
};
|
|
118
122
|
debug: boolean;
|
|
119
123
|
auth: {
|
|
120
|
-
credentials?: boolean | undefined;
|
|
121
124
|
debug?: boolean | undefined;
|
|
125
|
+
credentials?: boolean | undefined;
|
|
122
126
|
secret?: string | undefined;
|
|
123
127
|
secure_cookies?: boolean | undefined;
|
|
124
128
|
};
|
|
@@ -129,18 +133,18 @@ export declare const Config: z.ZodObject<{
|
|
|
129
133
|
user?: string | undefined;
|
|
130
134
|
database?: string | undefined;
|
|
131
135
|
};
|
|
132
|
-
log: {
|
|
133
|
-
level?: "debug" | "error" | "warn" | "notice" | "info" | undefined;
|
|
134
|
-
console?: boolean | undefined;
|
|
135
|
-
};
|
|
136
136
|
web: {
|
|
137
137
|
prefix?: string | undefined;
|
|
138
138
|
};
|
|
139
139
|
}, {
|
|
140
|
+
log: {
|
|
141
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
142
|
+
console?: boolean | undefined;
|
|
143
|
+
};
|
|
140
144
|
debug: boolean;
|
|
141
145
|
auth: {
|
|
142
|
-
credentials?: boolean | undefined;
|
|
143
146
|
debug?: boolean | undefined;
|
|
147
|
+
credentials?: boolean | undefined;
|
|
144
148
|
secret?: string | undefined;
|
|
145
149
|
secure_cookies?: boolean | undefined;
|
|
146
150
|
};
|
|
@@ -151,10 +155,6 @@ export declare const Config: z.ZodObject<{
|
|
|
151
155
|
user?: string | undefined;
|
|
152
156
|
database?: string | undefined;
|
|
153
157
|
};
|
|
154
|
-
log: {
|
|
155
|
-
level?: "debug" | "error" | "warn" | "notice" | "info" | undefined;
|
|
156
|
-
console?: boolean | undefined;
|
|
157
|
-
};
|
|
158
158
|
web: {
|
|
159
159
|
prefix?: string | undefined;
|
|
160
160
|
};
|
|
@@ -166,13 +166,13 @@ export declare const File: z.ZodObject<z.objectUtil.extendShape<{
|
|
|
166
166
|
secret: z.ZodOptional<z.ZodOptional<z.ZodString>>;
|
|
167
167
|
secure_cookies: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
168
168
|
}, "strip", z.ZodTypeAny, {
|
|
169
|
-
credentials?: boolean | undefined;
|
|
170
169
|
debug?: boolean | undefined;
|
|
170
|
+
credentials?: boolean | undefined;
|
|
171
171
|
secret?: string | undefined;
|
|
172
172
|
secure_cookies?: boolean | undefined;
|
|
173
173
|
}, {
|
|
174
|
-
credentials?: boolean | undefined;
|
|
175
174
|
debug?: boolean | undefined;
|
|
175
|
+
credentials?: boolean | undefined;
|
|
176
176
|
secret?: string | undefined;
|
|
177
177
|
secure_cookies?: boolean | undefined;
|
|
178
178
|
}>>;
|
|
@@ -200,10 +200,10 @@ export declare const File: z.ZodObject<z.objectUtil.extendShape<{
|
|
|
200
200
|
level: z.ZodOptional<z.ZodOptional<z.ZodEnum<["error", "warn", "notice", "info", "debug"]>>>;
|
|
201
201
|
console: z.ZodOptional<z.ZodOptional<z.ZodBoolean>>;
|
|
202
202
|
}, "strip", z.ZodTypeAny, {
|
|
203
|
-
level?: "
|
|
203
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
204
204
|
console?: boolean | undefined;
|
|
205
205
|
}, {
|
|
206
|
-
level?: "
|
|
206
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
207
207
|
console?: boolean | undefined;
|
|
208
208
|
}>>;
|
|
209
209
|
web: z.ZodOptional<z.ZodObject<{
|
|
@@ -216,10 +216,14 @@ export declare const File: z.ZodObject<z.objectUtil.extendShape<{
|
|
|
216
216
|
}, {
|
|
217
217
|
include: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
218
218
|
}>, "strip", z.ZodTypeAny, {
|
|
219
|
+
log?: {
|
|
220
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
221
|
+
console?: boolean | undefined;
|
|
222
|
+
} | undefined;
|
|
219
223
|
debug?: boolean | undefined;
|
|
220
224
|
auth?: {
|
|
221
|
-
credentials?: boolean | undefined;
|
|
222
225
|
debug?: boolean | undefined;
|
|
226
|
+
credentials?: boolean | undefined;
|
|
223
227
|
secret?: string | undefined;
|
|
224
228
|
secure_cookies?: boolean | undefined;
|
|
225
229
|
} | undefined;
|
|
@@ -230,19 +234,19 @@ export declare const File: z.ZodObject<z.objectUtil.extendShape<{
|
|
|
230
234
|
user?: string | undefined;
|
|
231
235
|
database?: string | undefined;
|
|
232
236
|
} | undefined;
|
|
233
|
-
log?: {
|
|
234
|
-
level?: "debug" | "error" | "warn" | "notice" | "info" | undefined;
|
|
235
|
-
console?: boolean | undefined;
|
|
236
|
-
} | undefined;
|
|
237
237
|
web?: {
|
|
238
238
|
prefix?: string | undefined;
|
|
239
239
|
} | undefined;
|
|
240
240
|
include?: string[] | undefined;
|
|
241
241
|
}, {
|
|
242
|
+
log?: {
|
|
243
|
+
level?: "warn" | "error" | "debug" | "notice" | "info" | undefined;
|
|
244
|
+
console?: boolean | undefined;
|
|
245
|
+
} | undefined;
|
|
242
246
|
debug?: boolean | undefined;
|
|
243
247
|
auth?: {
|
|
244
|
-
credentials?: boolean | undefined;
|
|
245
248
|
debug?: boolean | undefined;
|
|
249
|
+
credentials?: boolean | undefined;
|
|
246
250
|
secret?: string | undefined;
|
|
247
251
|
secure_cookies?: boolean | undefined;
|
|
248
252
|
} | undefined;
|
|
@@ -253,10 +257,6 @@ export declare const File: z.ZodObject<z.objectUtil.extendShape<{
|
|
|
253
257
|
user?: string | undefined;
|
|
254
258
|
database?: string | undefined;
|
|
255
259
|
} | undefined;
|
|
256
|
-
log?: {
|
|
257
|
-
level?: "debug" | "error" | "warn" | "notice" | "info" | undefined;
|
|
258
|
-
console?: boolean | undefined;
|
|
259
|
-
} | undefined;
|
|
260
260
|
web?: {
|
|
261
261
|
prefix?: string | undefined;
|
|
262
262
|
} | undefined;
|
package/dist/config.js
CHANGED
|
@@ -90,7 +90,7 @@ export function load(path, options = {}) {
|
|
|
90
90
|
catch (e) {
|
|
91
91
|
if (!options.optional)
|
|
92
92
|
throw e;
|
|
93
|
-
|
|
93
|
+
debug && output.debug(`Skipping config at ${path} (${e.message})`);
|
|
94
94
|
return;
|
|
95
95
|
}
|
|
96
96
|
const config = options.strict ? File.parse(json) : json;
|
|
@@ -116,7 +116,7 @@ export function saveTo(path, changed) {
|
|
|
116
116
|
set(changed);
|
|
117
117
|
const config = files.get(path) ?? {};
|
|
118
118
|
Object.assign(config, { ...changed, db: { ...config.db, ...changed.db } });
|
|
119
|
-
|
|
119
|
+
debug && output.debug(`Wrote config to ${path}`);
|
|
120
120
|
writeFileSync(path, JSON.stringify(config));
|
|
121
121
|
}
|
|
122
122
|
/**
|
package/dist/database.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AdapterAccountType as db } from '@auth/core/adapters';
|
|
|
2
2
|
import { Kysely, type GeneratedAlways } from 'kysely';
|
|
3
3
|
import type { Preferences } from './auth.js';
|
|
4
4
|
import * as config from './config.js';
|
|
5
|
+
import { type MaybeOutput } from './io.js';
|
|
5
6
|
export interface Schema {
|
|
6
7
|
User: {
|
|
7
8
|
id: GeneratedAlways<string>;
|
|
@@ -58,15 +59,9 @@ export interface Stats {
|
|
|
58
59
|
}
|
|
59
60
|
export declare function status(): Promise<Stats>;
|
|
60
61
|
export declare function statusText(): Promise<string>;
|
|
61
|
-
export
|
|
62
|
-
export type OpOutput = {
|
|
63
|
-
(state: 'done'): void;
|
|
64
|
-
(state: Exclude<OpOutputState, 'done'>, message: string): void;
|
|
65
|
-
};
|
|
66
|
-
export interface OpOptions {
|
|
62
|
+
export interface OpOptions extends MaybeOutput {
|
|
67
63
|
timeout: number;
|
|
68
64
|
force: boolean;
|
|
69
|
-
output?: OpOutput;
|
|
70
65
|
}
|
|
71
66
|
export interface InitOptions extends OpOptions {
|
|
72
67
|
skip: boolean;
|
package/dist/database.js
CHANGED
|
@@ -55,7 +55,7 @@ import { exec } from 'node:child_process';
|
|
|
55
55
|
import { randomBytes } from 'node:crypto';
|
|
56
56
|
import pg from 'pg';
|
|
57
57
|
import * as config from './config.js';
|
|
58
|
-
import {
|
|
58
|
+
import { _fixOutput } from './io.js';
|
|
59
59
|
export let database;
|
|
60
60
|
export function connect() {
|
|
61
61
|
if (database)
|
|
@@ -87,12 +87,6 @@ export async function statusText() {
|
|
|
87
87
|
throw typeof error == 'object' && 'message' in error ? error.message : error;
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
|
-
/**
|
|
91
|
-
* TS can't tell when we do this inline
|
|
92
|
-
*/
|
|
93
|
-
function _fixOutput(opt) {
|
|
94
|
-
opt.output ??= () => { };
|
|
95
|
-
}
|
|
96
90
|
/**
|
|
97
91
|
* Convenience function for `sudo -u postgres psql -c "${command}"`, plus `report` coolness.
|
|
98
92
|
* @internal
|
|
@@ -134,7 +128,7 @@ export async function init(opt) {
|
|
|
134
128
|
_fixOutput(opt);
|
|
135
129
|
if (!config.db.password) {
|
|
136
130
|
config.save({ db: { password: randomBytes(32).toString('base64') } }, true);
|
|
137
|
-
|
|
131
|
+
opt.output('debug', 'Generated password and wrote to global config');
|
|
138
132
|
}
|
|
139
133
|
const _sql = (command, message) => execSQL(opt, command, message);
|
|
140
134
|
await _sql('CREATE DATABASE axium', 'Creating database').catch(async (error) => {
|
package/dist/io.d.ts
CHANGED
|
@@ -19,3 +19,41 @@ export declare const output: {
|
|
|
19
19
|
export declare function exit(message: string | Error, code?: number): never;
|
|
20
20
|
/** Convenience function for `example... [done. / error]` */
|
|
21
21
|
export declare function report<T>(promise: Promise<T>, message: string, success?: string): Promise<T>;
|
|
22
|
+
export type OutputState = 'done' | 'log' | 'warn' | 'error' | 'start' | 'debug';
|
|
23
|
+
export interface Output {
|
|
24
|
+
(state: 'done'): void;
|
|
25
|
+
(state: Exclude<OutputState, 'done'>, message: string): void;
|
|
26
|
+
}
|
|
27
|
+
export interface MaybeOutput {
|
|
28
|
+
output?: Output | null | false;
|
|
29
|
+
}
|
|
30
|
+
export interface WithOutput {
|
|
31
|
+
output: Output;
|
|
32
|
+
}
|
|
33
|
+
export declare function defaultOutput(state: 'done'): void;
|
|
34
|
+
export declare function defaultOutput(state: Exclude<OutputState, 'done'>, message: string): void;
|
|
35
|
+
/**
|
|
36
|
+
* TS can't tell when we do this inline
|
|
37
|
+
* @internal
|
|
38
|
+
*/
|
|
39
|
+
export declare function _fixOutput<T extends MaybeOutput>(opt: T): asserts opt is T & WithOutput;
|
|
40
|
+
/** @internal */
|
|
41
|
+
export declare const _portMethods: readonly ["node-cap"];
|
|
42
|
+
/** @internal */
|
|
43
|
+
export declare const _portActions: readonly ["enable", "disable"];
|
|
44
|
+
/**
|
|
45
|
+
* Options for working with restricted ports.
|
|
46
|
+
*
|
|
47
|
+
* Method:
|
|
48
|
+
* - `node-cap`: Use the `cap_net_bind_service` capability on the node binary.
|
|
49
|
+
*/
|
|
50
|
+
export interface PortOptions extends MaybeOutput {
|
|
51
|
+
method: (typeof _portMethods)[number];
|
|
52
|
+
action: (typeof _portActions)[number];
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* This changes if Axium can use restricted ports (like 80 and 443) without root privileges.
|
|
56
|
+
* Use of these ports is needed so the origin doesn't have a port.
|
|
57
|
+
* If the origin has a port, passkeys do not work correctly with some password managers.
|
|
58
|
+
*/
|
|
59
|
+
export declare function restrictedPorts(opt: PortOptions): void;
|
package/dist/io.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { Logger } from 'logzen';
|
|
2
|
-
import {
|
|
2
|
+
import { execSync } from 'node:child_process';
|
|
3
|
+
import * as fs from 'node:fs';
|
|
3
4
|
import { homedir } from 'node:os';
|
|
4
5
|
import { join } from 'node:path/posix';
|
|
5
6
|
import { styleText } from 'node:util';
|
|
7
|
+
import { debug } from './config.js';
|
|
6
8
|
/**
|
|
7
9
|
* Find the Axium directory.
|
|
8
10
|
* This directory includes things like config files, secrets, etc.
|
|
@@ -17,8 +19,8 @@ export function findDir(global) {
|
|
|
17
19
|
return '.axium';
|
|
18
20
|
}
|
|
19
21
|
if (process.getuid?.() === 0)
|
|
20
|
-
mkdirSync('/etc/axium', { recursive: true });
|
|
21
|
-
mkdirSync(findDir(false), { recursive: true });
|
|
22
|
+
fs.mkdirSync('/etc/axium', { recursive: true });
|
|
23
|
+
fs.mkdirSync(findDir(false), { recursive: true });
|
|
22
24
|
export const logger = new Logger({
|
|
23
25
|
hideWarningStack: true,
|
|
24
26
|
noGlobalConsole: true,
|
|
@@ -61,3 +63,91 @@ export async function report(promise, message, success = 'done.') {
|
|
|
61
63
|
throw typeof error == 'object' && 'message' in error ? error.message : error;
|
|
62
64
|
}
|
|
63
65
|
}
|
|
66
|
+
export function defaultOutput(state, message = '') {
|
|
67
|
+
switch (state) {
|
|
68
|
+
case 'start':
|
|
69
|
+
process.stdout.write(message + '... ');
|
|
70
|
+
break;
|
|
71
|
+
case 'debug':
|
|
72
|
+
debug && output.debug(message);
|
|
73
|
+
break;
|
|
74
|
+
case 'log':
|
|
75
|
+
console.log(message);
|
|
76
|
+
break;
|
|
77
|
+
case 'warn':
|
|
78
|
+
process.stdout.write(styleText('yellow', message));
|
|
79
|
+
break;
|
|
80
|
+
case 'error':
|
|
81
|
+
process.stdout.write(styleText('red', message));
|
|
82
|
+
break;
|
|
83
|
+
case 'done':
|
|
84
|
+
console.log('done.');
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* TS can't tell when we do this inline
|
|
90
|
+
* @internal
|
|
91
|
+
*/
|
|
92
|
+
export function _fixOutput(opt) {
|
|
93
|
+
if (opt.output === false)
|
|
94
|
+
opt.output = () => { };
|
|
95
|
+
else
|
|
96
|
+
opt.output ??= defaultOutput;
|
|
97
|
+
}
|
|
98
|
+
/** @internal */
|
|
99
|
+
export const _portMethods = ['node-cap'];
|
|
100
|
+
/** @internal */
|
|
101
|
+
export const _portActions = ['enable', 'disable'];
|
|
102
|
+
/**
|
|
103
|
+
* This changes if Axium can use restricted ports (like 80 and 443) without root privileges.
|
|
104
|
+
* Use of these ports is needed so the origin doesn't have a port.
|
|
105
|
+
* If the origin has a port, passkeys do not work correctly with some password managers.
|
|
106
|
+
*/
|
|
107
|
+
export function restrictedPorts(opt) {
|
|
108
|
+
_fixOutput(opt);
|
|
109
|
+
opt.output('start', 'Checking for root privileges');
|
|
110
|
+
if (process.getuid?.() != 0)
|
|
111
|
+
throw 'root privileges are needed to change restricted ports.';
|
|
112
|
+
opt.output('done');
|
|
113
|
+
opt.output('start', 'Checking ports method');
|
|
114
|
+
if (!_portMethods.includes(opt.method))
|
|
115
|
+
throw 'invalid';
|
|
116
|
+
opt.output('done');
|
|
117
|
+
opt.output('start', 'Checking ports action');
|
|
118
|
+
if (!_portActions.includes(opt.action))
|
|
119
|
+
throw 'invalid';
|
|
120
|
+
opt.output('done');
|
|
121
|
+
switch (opt.method) {
|
|
122
|
+
case 'node-cap': {
|
|
123
|
+
opt.output('start', 'Finding setcap');
|
|
124
|
+
let setcap = execSync('command -v setcap', { encoding: 'utf-8' }).trim();
|
|
125
|
+
if (setcap)
|
|
126
|
+
opt.output('done');
|
|
127
|
+
else {
|
|
128
|
+
opt.output('warn', 'not in path.');
|
|
129
|
+
opt.output('start', 'Checking for /usr/sbin/setcap');
|
|
130
|
+
fs.accessSync('/usr/sbin/setcap', fs.constants.X_OK);
|
|
131
|
+
setcap = '/usr/sbin/setcap';
|
|
132
|
+
opt.output('done');
|
|
133
|
+
}
|
|
134
|
+
opt.output('debug', 'Using setup at ' + setcap);
|
|
135
|
+
opt.output('start', 'Finding node');
|
|
136
|
+
let node = execSync('command -v node', { encoding: 'utf-8' }).trim();
|
|
137
|
+
if (node)
|
|
138
|
+
opt.output('done');
|
|
139
|
+
else {
|
|
140
|
+
opt.output('warn', 'not in path.');
|
|
141
|
+
opt.output('start', 'Checking for /usr/bin/node');
|
|
142
|
+
fs.accessSync('/usr/bin/node', fs.constants.X_OK);
|
|
143
|
+
node = '/usr/bin/node';
|
|
144
|
+
opt.output('done');
|
|
145
|
+
}
|
|
146
|
+
opt.output('debug', 'Using node at ' + node);
|
|
147
|
+
opt.output('start', 'Setting ports capability');
|
|
148
|
+
execSync(`${setcap} cap_net_bind_service=${opt.action == 'enable' ? '+' : '-'}ep ${node}`, { encoding: 'utf-8' });
|
|
149
|
+
opt.output('done');
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|