Repository navigation
Expand file tree
/
Copy pathSystemConfigOverride.js
More file actions
145 lines (135 loc) · 6.61 KB
/
Copy pathSystemConfigOverride.js
File metadata and controls
145 lines (135 loc) · 6.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*
* GNU AGPL-3.0 License
*
* Copyright (c) 2021 - present core.ai . All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
* for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
*
*/
/**
* Reads `phoenix_override_config.json` from a machine wide, admin owned location and exposes the
* values in it as overrides for `brackets.config`. This is only available in the desktop app.
*
* The file lives in a directory that only an administrator/root can write to, so the presence of
* the file is itself the proof that a machine admin put it there. A standard user cannot create it,
* which is what stops a random extension or a downloaded project from pointing the app at an
* attacker controlled server.
*
* This is the shared "Phoenix Code Control" admin folder that machine wide policies should use going
* forward. It is a new folder, so it will not exist on already provisioned machines. The older AI
* disable policy still reads its own `Phoenix AI Control` folder(see phoenix-pro services/ai-control.js)
* and can be moved here later.
*
* Locations (create the directory as admin/root, then drop the file in):
* windows: C:\Program Files\Phoenix Code Control\phoenix_override_config.json
* mac : /Library/Application Support/Phoenix Code Control/phoenix_override_config.json
* linux : /etc/phoenix-code-control/phoenix_override_config.json
*
* File format - a flat json of `brackets.config` keys to override. Eg. to point the auto updater at
* a locally served update manifest:
* {
* "app_update_url": "http://localhost:8000/update-latest-experimental-build.json"
* }
*
* Only the keys listed in `OVERRIDABLE_KEYS` are honoured, everything else in the file is ignored.
*/
/*global logger*/
define(function (require, exports, module) {
const OVERRIDE_FILE_NAME = "phoenix_override_config.json";
// Only these `brackets.config` keys can be overridden from the system file. Keep this list
// as small as possible, add a key only when there is a real need to override it on a machine.
// reading this file must never be able to stall the app, see the race in getOverrides()
const READ_TIMEOUT_MS = 5000;
const OVERRIDABLE_KEYS = [
"app_update_url",
// linux installs by piping an installer script into bash, so the manifest's downloadURL is
// not enough there- this is what actually decides which build gets installed on linux.
"app_update_linux_installer_url",
// Lets an admin instrument a non dev build, for the one day named. A date rather than a
// flag because boot cannot read this file (no file reads on the boot path) and so reads a
// cached copy instead- a date means a cache left behind after this file is gone is
// worthless on any other day. Format is YYYY-MM-DD, see phoenix-builder/main.js.
"prodMCPOverrideDate"
];
/**
* Gets the platform specific path of the admin owned override file, or "" in non desktop builds.
* @returns {string} virtual path of the override file
*/
function _getOverrideFilePath() {
if (!Phoenix.isNativeApp) {
return "";
}
let platformPath;
if (Phoenix.platform === "win") {
platformPath = `C:\\Program Files\\Phoenix Code Control\\${OVERRIDE_FILE_NAME}`;
} else if (Phoenix.platform === "mac") {
platformPath = `/Library/Application Support/Phoenix Code Control/${OVERRIDE_FILE_NAME}`;
} else if (Phoenix.platform === "linux") {
platformPath = `/etc/phoenix-code-control/${OVERRIDE_FILE_NAME}`;
} else {
console.error("System config override: unsupported platform", Phoenix.platform);
return "";
}
return Phoenix.VFS.getTauriVirtualPath(platformPath);
}
const OVERRIDE_FILE_PATH = _getOverrideFilePath();
let overridesPromise = null;
/**
* Reads and parses the override file. The file is read once per app session and the result cached,
* so that an admin edit needs an app restart to take effect(same as any other boot config).
* Never rejects- a missing or malformed file just means "no overrides".
* @returns {Promise<Object>} the overridable key value pairs present in the file, may be empty
*/
function getOverrides() {
if (overridesPromise) {
return overridesPromise;
}
overridesPromise = (async function () {
if (!OVERRIDE_FILE_PATH) {
return {};
}
// Hard timeout. This is awaited on the app update path, including at quit time when
// the node process may already be gone, and a read that never settles would hang the
// quit. Timing out just means "no overrides", which is the normal case anyway.
const fileData = await Promise.race([
Phoenix.VFS.readFileResolves(OVERRIDE_FILE_PATH, "utf8"),
new Promise((resolve) => {
setTimeout(() => resolve({error: new Error("timed out")}), READ_TIMEOUT_MS);
})
]);
if (fileData.error || !fileData.data) {
// the common case, no admin has placed an override file on this machine.
return {};
}
try {
const rawOverrides = JSON.parse(fileData.data);
const overrides = {};
for (const key of OVERRIDABLE_KEYS) {
if (rawOverrides[key] !== undefined) {
overrides[key] = rawOverrides[key];
}
}
console.warn(`System config override in effect from ${OVERRIDE_FILE_PATH}:`, overrides);
return overrides;
} catch (e) {
console.error(`Error parsing system config override ${OVERRIDE_FILE_PATH}`, e);
logger.reportError(e, "Error parsing system config override file");
return {};
}
}());
return overridesPromise;
}
exports.OVERRIDE_FILE_PATH = OVERRIDE_FILE_PATH;
exports.getOverrides = getOverrides;
});