Skip to content

Commit 0bc0409

Browse files
Add standalone option
1 parent cec312a commit 0bc0409

File tree

9 files changed

+799
-45
lines changed

9 files changed

+799
-45
lines changed

.eslintrc.js

Lines changed: 0 additions & 19 deletions
This file was deleted.

.eslintrc.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
{
2+
"parserOptions": {
3+
"sourceType": "module",
4+
"ecmaVersion": 2018
5+
},
6+
"env": {
7+
"node": true,
8+
"es6": true
9+
},
10+
"extends": ["eslint:recommended", "plugin:prettier/recommended"],
11+
"rules": {
12+
"no-ex-assign": "off",
13+
"no-var":"error",
14+
"object-shorthand": ["warn", "always"],
15+
"prettier/prettier": ["warn", {"bracketSpacing": false, "trailingComma": "es5"}]
16+
},
17+
"overrides": [
18+
{
19+
"files": ["*.test.js"],
20+
"env": {
21+
"jest": true
22+
}
23+
}
24+
],
25+
"root": true
26+
}

bin/observable-database-proxy.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,20 @@ argv
1717
name,
1818
start
1919
)
20-
.command(`add <name>`, `Add a new database proxy configuration`, name, add)
20+
.command(
21+
`add <name> [--standalone]`,
22+
`Add a new database proxy configuration`,
23+
name,
24+
add
25+
)
2126
.command(
2227
`remove <name>`,
2328
`Remove an existing database proxy configuration`,
2429
name,
2530
remove
2631
)
2732
.command(
28-
`reset <name>`,
33+
`reset <name> [--standalone]`,
2934
`Reset the shared secret for an existing database proxy configuration`,
3035
name,
3136
reset
@@ -40,6 +45,10 @@ argv
4045
`sslkey`,
4146
`Set the SSL private key location for an HTTPS database proxy`
4247
)
48+
.describe(
49+
`standalone`,
50+
`Standalone mode: create a secret for standalone clients`
51+
)
4352
.example(`$0 start localdb`, `Run an HTTP database proxy named "localdb"`)
4453
.example(
4554
`$0 start localssl --sslkey ../ssl/localhost.key --sslcert ../ssl/localhost.crt`,

lib/commands.js

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
/* eslint-disable no-console */
22

3+
import {randomBytes} from "crypto";
34
import {createInterface} from "readline";
45
import open from "open";
56
import {
67
readConfig,
78
readDecodedConfig,
89
writeConfig,
910
decodeSecret,
11+
encodeSecret,
1012
} from "./config.js";
11-
import {server} from "./server.js";
13+
import {server, types} from "./server.js";
1214
import {exit} from "./errors.js";
1315

1416
export function start(argv) {
@@ -17,7 +19,7 @@ export function start(argv) {
1719
}
1820

1921
export async function add(argv, reset = false) {
20-
const {name, sslkey, sslcert} = argv;
22+
const {name, sslkey, sslcert, standalone} = argv;
2123
let config = readConfig();
2224
let url;
2325
let token;
@@ -39,7 +41,12 @@ export async function add(argv, reset = false) {
3941
if (reset) {
4042
if (!config[name]) exit(`No configuration found for "${name}"`);
4143
url = config[name].url;
42-
} else {
44+
token = config[name].token;
45+
server_host = config[name].server_host;
46+
path = config[name].path;
47+
username = config[name].username;
48+
password = config[name].password;
49+
} else if (!standalone) {
4350
const wantsSSL = sslkey || sslcert;
4451
// open browser
4552
const observable =
@@ -53,8 +60,50 @@ export async function add(argv, reset = false) {
5360
);
5461
}
5562

56-
// paste secret (secret, origin, name, type, host, port, ssl)
57-
const secret = await question("Secret: ");
63+
let secret;
64+
if (standalone) {
65+
let {type, host, origin, port, ssl} = reset
66+
? decodeSecret(config[name].secret)
67+
: {};
68+
if (!type) {
69+
for (;;) {
70+
type = await question("Database type: ");
71+
if (types.includes(type)) break;
72+
console.log(`Invalid type, should be one of: ${types.join(", ")}`);
73+
}
74+
} else if (!types.includes(type)) {
75+
exit(`Invalid type, should be one of: ${type.join(", ")}`);
76+
}
77+
if (!host || !port || !ssl) {
78+
const proxyUrl = new URL(
79+
(await question(
80+
"Observable database proxy Url [http://127.0.0.1:2899]:"
81+
)) || "http://127.0.0.1:2899"
82+
);
83+
host = proxyUrl.hostname;
84+
port = proxyUrl.port;
85+
ssl = proxyUrl.protocol !== "https" ? "disabled" : "required";
86+
}
87+
if (!origin) {
88+
origin =
89+
(await question("Standalone server origin [http://127.0.0.1:3000]:")) ||
90+
"http://127.0.0.1:3000";
91+
}
92+
93+
const secretPayload = {
94+
name,
95+
type,
96+
host,
97+
port,
98+
ssl,
99+
origin,
100+
secret: randomBytes(32).toString("hex"),
101+
};
102+
secret = encodeSecret(secretPayload);
103+
} else {
104+
// paste secret (secret, origin, name, type, host, port, ssl)
105+
secret = await question("Secret: ");
106+
}
58107
const decoded = decodeSecret(secret);
59108
if (decoded.name !== name)
60109
return exit(`Name mismatch: "${decoded.name}" (server), "${name} (proxy)"`);
@@ -104,6 +153,8 @@ export async function add(argv, reset = false) {
104153
writeConfig(config);
105154

106155
console.log(`Configuration ${reset ? `reset` : `added`} for "${name}"`);
156+
if (standalone)
157+
console.log(`Secret for DabaseClient("${name}"):\ndb:${name}:${secret}`);
107158
}
108159

109160
export function reset(argv) {

lib/config.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,8 @@ export function decodeSecret(secret) {
5656
exit(error);
5757
}
5858
}
59+
60+
export function encodeSecret(arg) {
61+
const buffer = Buffer.from(JSON.stringify(arg)).toString("base64");
62+
return buffer;
63+
}

lib/server.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,19 @@ import oracle from "./oracle.js";
1616
import databricks from "./databricks.js";
1717
import logger from "../middleware/logger.js";
1818

19+
export const types = [
20+
"databricks",
21+
"mysql",
22+
"mssql",
23+
"postgres",
24+
"snowflake",
25+
"oracle",
26+
"mongosql",
27+
];
28+
1929
export async function server(config, argv) {
2030
const development = process.env.NODE_ENV === "development";
21-
const developmentOrigin = "https://worker.test:5000";
31+
const developmentOrigin = "https://login.worker.test:5000";
2232

2333
const {
2434
name,

lib/validate.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export const validateQueryPayload = ajv.compile({
88
required: ["sql"],
99
properties: {
1010
sql: {type: "string", minLength: 1, maxLength: 32 * 1000},
11-
params: {type: ["object", "array"]},
11+
params: {anyOf: [{type: ["object"]}, {type: ["array"]}]}
1212
},
1313
});
1414
export const validateDescribeColumnsPayload = ajv.compile({

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,10 +36,14 @@
3636
"@babel/preset-env": "^7.19.4",
3737
"@babel/register": "^7.18.9",
3838
"chai": "^4.3.6",
39+
"eslint": "^8.50.0",
40+
"eslint-config-prettier": "^9.0.0",
41+
"eslint-plugin-prettier": "^5.0.0",
3942
"mocha": "^10.1.0",
4043
"mock-req": "^0.2.0",
4144
"mock-res": "^0.6.0",
4245
"nodemon": "^1.19.1",
46+
"prettier": "^3.0.3",
4347
"wait-on": "^6.0.1"
4448
},
4549
"peerDependencies": {

0 commit comments

Comments
 (0)