docker-client-mx 1.35.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/LICENSE +21 -0
- package/README.md +233 -0
- package/bin/docker-client-mx.js +42 -0
- package/build/icons/icon-1024.png +0 -0
- package/build/icons/icon-128.png +0 -0
- package/build/icons/icon-16.png +0 -0
- package/build/icons/icon-256.png +0 -0
- package/build/icons/icon-32.png +0 -0
- package/build/icons/icon-48.png +0 -0
- package/build/icons/icon-512.png +0 -0
- package/build/icons/icon-64.png +0 -0
- package/build/icons/icon.ico +0 -0
- package/build/icons/icon.iconset/icon_128x128.png +0 -0
- package/build/icons/icon.iconset/icon_128x128@2x.png +0 -0
- package/build/icons/icon.iconset/icon_16x16.png +0 -0
- package/build/icons/icon.iconset/icon_16x16@2x.png +0 -0
- package/build/icons/icon.iconset/icon_256x256.png +0 -0
- package/build/icons/icon.iconset/icon_256x256@2x.png +0 -0
- package/build/icons/icon.iconset/icon_32x32.png +0 -0
- package/build/icons/icon.iconset/icon_32x32@2x.png +0 -0
- package/build/icons/icon.iconset/icon_512x512.png +0 -0
- package/build/icons/icon.iconset/icon_512x512@2x.png +0 -0
- package/build/icons/icon.png +0 -0
- package/dist/docker-desktop-mx/browser/chunk-64WWLMUP.js +39 -0
- package/dist/docker-desktop-mx/browser/chunk-N4VBBC4W.js +1 -0
- package/dist/docker-desktop-mx/browser/favicon.ico +0 -0
- package/dist/docker-desktop-mx/browser/index.html +14 -0
- package/dist/docker-desktop-mx/browser/main-CTIRTSOI.js +5 -0
- package/dist/docker-desktop-mx/browser/styles-JS3HDDI4.css +1 -0
- package/dist-electron/api.js +10 -0
- package/dist-electron/api.js.map +1 -0
- package/dist-electron/assistant-key.js +70 -0
- package/dist-electron/assistant-key.js.map +1 -0
- package/dist-electron/assistant-models.js +19 -0
- package/dist-electron/assistant-models.js.map +1 -0
- package/dist-electron/assistant-tools.js +335 -0
- package/dist-electron/assistant-tools.js.map +1 -0
- package/dist-electron/assistant.js +302 -0
- package/dist-electron/assistant.js.map +1 -0
- package/dist-electron/attention.js +75 -0
- package/dist-electron/attention.js.map +1 -0
- package/dist-electron/channels.js +113 -0
- package/dist-electron/channels.js.map +1 -0
- package/dist-electron/compose-files.js +104 -0
- package/dist-electron/compose-files.js.map +1 -0
- package/dist-electron/compose.js +271 -0
- package/dist-electron/compose.js.map +1 -0
- package/dist-electron/container-events.js +188 -0
- package/dist-electron/container-events.js.map +1 -0
- package/dist-electron/containers.js +165 -0
- package/dist-electron/containers.js.map +1 -0
- package/dist-electron/context-menu.js +56 -0
- package/dist-electron/context-menu.js.map +1 -0
- package/dist-electron/contexts.js +346 -0
- package/dist-electron/contexts.js.map +1 -0
- package/dist-electron/crash.js +129 -0
- package/dist-electron/crash.js.map +1 -0
- package/dist-electron/diagnosis.js +338 -0
- package/dist-electron/diagnosis.js.map +1 -0
- package/dist-electron/docker-client.js +284 -0
- package/dist-electron/docker-client.js.map +1 -0
- package/dist-electron/engine.js +145 -0
- package/dist-electron/engine.js.map +1 -0
- package/dist-electron/event-store.js +146 -0
- package/dist-electron/event-store.js.map +1 -0
- package/dist-electron/events.js +132 -0
- package/dist-electron/events.js.map +1 -0
- package/dist-electron/exec.js +138 -0
- package/dist-electron/exec.js.map +1 -0
- package/dist-electron/files.js +407 -0
- package/dist-electron/files.js.map +1 -0
- package/dist-electron/health.js +92 -0
- package/dist-electron/health.js.map +1 -0
- package/dist-electron/host-overview.js +50 -0
- package/dist-electron/host-overview.js.map +1 -0
- package/dist-electron/host-shell.js +196 -0
- package/dist-electron/host-shell.js.map +1 -0
- package/dist-electron/i18n.js +58 -0
- package/dist-electron/i18n.js.map +1 -0
- package/dist-electron/image-history.js +87 -0
- package/dist-electron/image-history.js.map +1 -0
- package/dist-electron/images.js +141 -0
- package/dist-electron/images.js.map +1 -0
- package/dist-electron/ipc.js +783 -0
- package/dist-electron/ipc.js.map +1 -0
- package/dist-electron/links.js +46 -0
- package/dist-electron/links.js.map +1 -0
- package/dist-electron/logs.js +153 -0
- package/dist-electron/logs.js.map +1 -0
- package/dist-electron/main.js +494 -0
- package/dist-electron/main.js.map +1 -0
- package/dist-electron/merged-logs.js +127 -0
- package/dist-electron/merged-logs.js.map +1 -0
- package/dist-electron/navigation.js +37 -0
- package/dist-electron/navigation.js.map +1 -0
- package/dist-electron/ndjson.js +30 -0
- package/dist-electron/ndjson.js.map +1 -0
- package/dist-electron/networks.js +507 -0
- package/dist-electron/networks.js.map +1 -0
- package/dist-electron/port-conflicts.js +106 -0
- package/dist-electron/port-conflicts.js.map +1 -0
- package/dist-electron/preload.js +257 -0
- package/dist-electron/preload.js.map +1 -0
- package/dist-electron/pull.js +220 -0
- package/dist-electron/pull.js.map +1 -0
- package/dist-electron/redact.js +129 -0
- package/dist-electron/redact.js.map +1 -0
- package/dist-electron/registry-auth.js +150 -0
- package/dist-electron/registry-auth.js.map +1 -0
- package/dist-electron/renew.js +162 -0
- package/dist-electron/renew.js.map +1 -0
- package/dist-electron/restart-policy.js +58 -0
- package/dist-electron/restart-policy.js.map +1 -0
- package/dist-electron/run-command.js +146 -0
- package/dist-electron/run-command.js.map +1 -0
- package/dist-electron/run.js +151 -0
- package/dist-electron/run.js.map +1 -0
- package/dist-electron/self-update.js +163 -0
- package/dist-electron/self-update.js.map +1 -0
- package/dist-electron/servers.js +108 -0
- package/dist-electron/servers.js.map +1 -0
- package/dist-electron/settings.js +146 -0
- package/dist-electron/settings.js.map +1 -0
- package/dist-electron/ssh.js +574 -0
- package/dist-electron/ssh.js.map +1 -0
- package/dist-electron/stats.js +209 -0
- package/dist-electron/stats.js.map +1 -0
- package/dist-electron/streams.js +63 -0
- package/dist-electron/streams.js.map +1 -0
- package/dist-electron/system.js +123 -0
- package/dist-electron/system.js.map +1 -0
- package/dist-electron/terminal-transcript.js +55 -0
- package/dist-electron/terminal-transcript.js.map +1 -0
- package/dist-electron/updates.js +136 -0
- package/dist-electron/updates.js.map +1 -0
- package/dist-electron/volume-backup.js +203 -0
- package/dist-electron/volume-backup.js.map +1 -0
- package/dist-electron/volume-files.js +124 -0
- package/dist-electron/volume-files.js.map +1 -0
- package/dist-electron/volumes.js +253 -0
- package/dist-electron/volumes.js.map +1 -0
- package/dist-electron/wiring-watch.js +93 -0
- package/dist-electron/wiring-watch.js.map +1 -0
- package/dist-electron/wiring.js +71 -0
- package/dist-electron/wiring.js.map +1 -0
- package/dist-electron/wsl.js +167 -0
- package/dist-electron/wsl.js.map +1 -0
- package/package.json +125 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.redacted = redacted;
|
|
4
|
+
exports.redactArgs = redactArgs;
|
|
5
|
+
exports.redactText = redactText;
|
|
6
|
+
exports.redactEnv = redactEnv;
|
|
7
|
+
const i18n_1 = require("./i18n");
|
|
8
|
+
/**
|
|
9
|
+
* Haalt geheimen uit tekst die de app buiten de deur laat gaan: de diagnose die je in een chat
|
|
10
|
+
* of een issue plakt.
|
|
11
|
+
*
|
|
12
|
+
* Liever te veel weg dan te weinig. Een waarde die ten onrechte weg is, kost de lezer een vraag;
|
|
13
|
+
* een wachtwoord dat erin blijft staan, staat daarna in een chatgeschiedenis of een openbaar
|
|
14
|
+
* issue en is niet meer terug te halen.
|
|
15
|
+
*/
|
|
16
|
+
/** Wat er op de plek van een geheim komt te staan, in de taal van de app. */
|
|
17
|
+
function redacted() {
|
|
18
|
+
return (0, i18n_1.t)({ en: '<omitted>', nl: '<weggelaten>', de: '<ausgelassen>', fr: '<omis>', es: '<omitido>' });
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Namen die op een geheim wijzen, als deel van een langere naam: `DB_PASSWORD`, `apiKey`,
|
|
22
|
+
* `client_secret`, `traefik.….basicauth.users`. Geen kale `auth`: dan valt ook `author` eronder.
|
|
23
|
+
*/
|
|
24
|
+
const SECRET_NAME = String.raw `(?:pass(?:word|wd|phrase)?|pwd|secret|token|api[_-]?key|access[_-]?key|private[_-]?key|credentials?|basicauth|htpasswd)`;
|
|
25
|
+
/**
|
|
26
|
+
* In deze volgorde: eerst wat een herkenbare vorm heeft, dan `naam=waarde`. Een regel slaat
|
|
27
|
+
* over wat een eerdere al weggelaten heeft, zodat niets dubbel geteld wordt.
|
|
28
|
+
*/
|
|
29
|
+
const RULES = [
|
|
30
|
+
// Een hele private key, over meerdere regels.
|
|
31
|
+
{
|
|
32
|
+
pattern: /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?-----END [A-Z ]*PRIVATE KEY-----/g,
|
|
33
|
+
replace: () => redacted(),
|
|
34
|
+
},
|
|
35
|
+
// Een wachtwoord in een url: postgres://app:geheim@db:5432/app.
|
|
36
|
+
{
|
|
37
|
+
pattern: /\b([a-z][a-z0-9+.-]*:\/\/[^\s:@/]+):([^\s@/]+)@/gi,
|
|
38
|
+
replace: (_match, before) => `${before}:${redacted()}@`,
|
|
39
|
+
},
|
|
40
|
+
// Een token als enige gegeven voor de @, zoals in een git-remote:
|
|
41
|
+
// https://ghp_AbCd…@github.com/org/repo.git. Pas vanaf acht tekens, zodat user@host in een
|
|
42
|
+
// gewone url (ssh://git@github.com) blijft staan.
|
|
43
|
+
{
|
|
44
|
+
pattern: /\b([a-z][a-z0-9+.-]*:\/\/)([^\s:@/<>]{8,})@/gi,
|
|
45
|
+
replace: (_match, scheme) => `${scheme}${redacted()}@`,
|
|
46
|
+
},
|
|
47
|
+
// Een token achter Bearer, Basic of Token, zoals in een Authorization-header.
|
|
48
|
+
{
|
|
49
|
+
pattern: /\b(Bearer|Basic|Token)\s+([A-Za-z0-9._~+/=-]{8,})/g,
|
|
50
|
+
replace: (_match, scheme) => `${scheme} ${redacted()}`,
|
|
51
|
+
},
|
|
52
|
+
// Een JWT, ook zonder Bearer ervoor: drie base64url-delen, de eerste begint met {"…
|
|
53
|
+
{
|
|
54
|
+
pattern: /\beyJ[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}\.[A-Za-z0-9_-]{5,}/g,
|
|
55
|
+
replace: () => redacted(),
|
|
56
|
+
},
|
|
57
|
+
// Een access key van AWS.
|
|
58
|
+
{
|
|
59
|
+
pattern: /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g,
|
|
60
|
+
replace: () => redacted(),
|
|
61
|
+
},
|
|
62
|
+
// naam=waarde, naam: waarde en "naam": "waarde", waar de naam op een geheim wijst.
|
|
63
|
+
{
|
|
64
|
+
pattern: new RegExp(String.raw `(["']?)([\w.-]*${SECRET_NAME}[\w.-]*)\1(\s*[:=]\s*)(["']?)([^\s"',;&]+)\4`, 'gi'),
|
|
65
|
+
replace: (_match, quote, name, separator, valueQuote) => `${quote}${name}${quote}${separator}${valueQuote}${redacted()}${valueQuote}`,
|
|
66
|
+
},
|
|
67
|
+
// Een vlag met de waarde na een spatie: --password geheim. Niet als het volgende woord zelf
|
|
68
|
+
// een vlag is.
|
|
69
|
+
{
|
|
70
|
+
pattern: new RegExp(String.raw `(--?[\w-]*${SECRET_NAME}[\w-]*)(\s+)(?!-)(\S+)`, 'gi'),
|
|
71
|
+
replace: (_match, flag, space) => `${flag}${space}${redacted()}`,
|
|
72
|
+
},
|
|
73
|
+
];
|
|
74
|
+
const SECRET_FLAG = new RegExp(String.raw `^--?[\w-]*${SECRET_NAME}[\w-]*$`, 'i');
|
|
75
|
+
/**
|
|
76
|
+
* Een lijst argumenten zoals in `Cmd` of `Args`, waar `--token` en de waarde losse elementen
|
|
77
|
+
* zijn. Per element opschonen zou die combinatie missen.
|
|
78
|
+
*/
|
|
79
|
+
function redactArgs(args) {
|
|
80
|
+
let count = 0;
|
|
81
|
+
const result = args.map((arg, index) => {
|
|
82
|
+
const previous = args[index - 1];
|
|
83
|
+
if (previous !== undefined && SECRET_FLAG.test(previous) && !arg.startsWith('-')) {
|
|
84
|
+
count += 1;
|
|
85
|
+
return redacted();
|
|
86
|
+
}
|
|
87
|
+
const cleaned = redactText(arg);
|
|
88
|
+
count += cleaned.count;
|
|
89
|
+
return cleaned.text;
|
|
90
|
+
});
|
|
91
|
+
return { args: result, count };
|
|
92
|
+
}
|
|
93
|
+
/** Laat weg wat op een geheim lijkt, en telt hoeveel. */
|
|
94
|
+
function redactText(text) {
|
|
95
|
+
let count = 0;
|
|
96
|
+
let result = text;
|
|
97
|
+
for (const rule of RULES) {
|
|
98
|
+
result = result.replace(rule.pattern, (...args) => {
|
|
99
|
+
const match = String(args[0]);
|
|
100
|
+
const groups = args.slice(0, -2).map((group) => (typeof group === 'string' ? group : ''));
|
|
101
|
+
const replaced = rule.replace(...groups);
|
|
102
|
+
// Wat een eerdere regel al weghaalde (`password=<weggelaten>`), komt er ongewijzigd uit;
|
|
103
|
+
// dat telt niet nog een keer.
|
|
104
|
+
if (replaced === match) {
|
|
105
|
+
return match;
|
|
106
|
+
}
|
|
107
|
+
count += 1;
|
|
108
|
+
return replaced;
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
return { text: result, count };
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Van omgevingsvariabelen alleen de namen. Ook bij een naam die onschuldig lijkt:
|
|
115
|
+
* `DATABASE_URL` bevat meestal een wachtwoord, en `APP_KEY` heet niet eens zo.
|
|
116
|
+
*/
|
|
117
|
+
function redactEnv(entries) {
|
|
118
|
+
let count = 0;
|
|
119
|
+
const result = entries.map((entry) => {
|
|
120
|
+
const equals = entry.indexOf('=');
|
|
121
|
+
if (equals === -1 || equals === entry.length - 1) {
|
|
122
|
+
return entry;
|
|
123
|
+
}
|
|
124
|
+
count += 1;
|
|
125
|
+
return `${entry.slice(0, equals)}=${redacted()}`;
|
|
126
|
+
});
|
|
127
|
+
return { entries: result, count };
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=redact.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"redact.js","sourceRoot":"","sources":["../electron/redact.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.DOCKER_HUB = void 0;
|
|
37
|
+
exports.registryOf = registryOf;
|
|
38
|
+
exports.parseHelperOutput = parseHelperOutput;
|
|
39
|
+
exports.fromConfigAuths = fromConfigAuths;
|
|
40
|
+
exports.credentialsFor = credentialsFor;
|
|
41
|
+
const node_child_process_1 = require("node:child_process");
|
|
42
|
+
const node_fs_1 = require("node:fs");
|
|
43
|
+
const path = __importStar(require("node:path"));
|
|
44
|
+
const contexts_1 = require("./contexts");
|
|
45
|
+
/**
|
|
46
|
+
* De inloggegevens voor een registry, zoals de docker CLI ze zelf ook vindt.
|
|
47
|
+
*
|
|
48
|
+
* Wie `docker login` deed, heeft ze al: in een credential helper (`credsStore`, op Windows
|
|
49
|
+
* meestal `desktop` of `wincred`, die in de Windows-referentiebeheerder schrijven) of, zonder
|
|
50
|
+
* helper, base64 in `~/.docker/config.json`. Daarom hoeft deze app geen eigen inlogscherm te
|
|
51
|
+
* hebben, en bewaart hij zelf niets.
|
|
52
|
+
*
|
|
53
|
+
* Wat hier opgehaald wordt blijft in het main process: het gaat mee met de pull naar de daemon
|
|
54
|
+
* en komt nooit in de renderer of in een log.
|
|
55
|
+
*/
|
|
56
|
+
/** De sleutel waaronder Docker Hub in config.json en in de helpers staat. Historisch zo, niet `docker.io`. */
|
|
57
|
+
exports.DOCKER_HUB = 'https://index.docker.io/v1/';
|
|
58
|
+
/** Zolang mag een helper erover doen; de Windows-referentiebeheerder kan een prompt tonen. */
|
|
59
|
+
const HELPER_TIMEOUT_MS = 15_000;
|
|
60
|
+
/**
|
|
61
|
+
* Van welke registry een image komt. Docker's eigen regel: het eerste deel is alleen een
|
|
62
|
+
* registry als er een punt of dubbele punt in staat, of als het `localhost` is. `nginx` en
|
|
63
|
+
* `library/nginx` en `martijn/app` komen dus allemaal van Docker Hub.
|
|
64
|
+
*/
|
|
65
|
+
function registryOf(reference) {
|
|
66
|
+
const first = reference.split('/')[0];
|
|
67
|
+
if (reference.includes('/') && (first.includes('.') || first.includes(':') || first === 'localhost')) {
|
|
68
|
+
return first === 'docker.io' || first === 'index.docker.io' ? exports.DOCKER_HUB : first;
|
|
69
|
+
}
|
|
70
|
+
return exports.DOCKER_HUB;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Een helpernaam uit config.json wordt een programmanaam. Alleen letters, cijfers en een
|
|
74
|
+
* streepje: anders zou een aangepaste config een pad of een ander programma kunnen aanwijzen.
|
|
75
|
+
*/
|
|
76
|
+
function isHelperName(value) {
|
|
77
|
+
return typeof value === 'string' && /^[a-z0-9-]+$/i.test(value);
|
|
78
|
+
}
|
|
79
|
+
const runHelper = (helper, server) => new Promise((resolve, reject) => {
|
|
80
|
+
const child = (0, node_child_process_1.execFile)(`docker-credential-${helper}`, ['get'], { timeout: HELPER_TIMEOUT_MS, windowsHide: true }, (err, stdout) => {
|
|
81
|
+
if (err !== null) {
|
|
82
|
+
reject(new Error(err.message, { cause: err }));
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
resolve(stdout);
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
// Het protocol van de helpers: de registry op stdin, het antwoord als JSON op stdout.
|
|
89
|
+
child.stdin?.end(server);
|
|
90
|
+
});
|
|
91
|
+
/** Leest het antwoord van een helper. `<token>` als gebruikersnaam betekent: dit is een identity token. */
|
|
92
|
+
function parseHelperOutput(output, server) {
|
|
93
|
+
const parsed = JSON.parse(output);
|
|
94
|
+
if (typeof parsed.Secret !== 'string' || parsed.Secret === '') {
|
|
95
|
+
return null;
|
|
96
|
+
}
|
|
97
|
+
if (parsed.Username === '<token>') {
|
|
98
|
+
return { identitytoken: parsed.Secret, serveraddress: server };
|
|
99
|
+
}
|
|
100
|
+
return typeof parsed.Username === 'string' ? { username: parsed.Username, password: parsed.Secret, serveraddress: server } : null;
|
|
101
|
+
}
|
|
102
|
+
/** De gegevens die zonder helper in config.json zelf staan, als `user:pass` in base64. */
|
|
103
|
+
function fromConfigAuths(config, server) {
|
|
104
|
+
const entry = config.auths?.[server];
|
|
105
|
+
if (typeof entry?.identitytoken === 'string' && entry.identitytoken !== '') {
|
|
106
|
+
return { identitytoken: entry.identitytoken, serveraddress: server };
|
|
107
|
+
}
|
|
108
|
+
if (typeof entry?.auth !== 'string' || entry.auth === '') {
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
111
|
+
const decoded = Buffer.from(entry.auth, 'base64').toString('utf8');
|
|
112
|
+
const colon = decoded.indexOf(':');
|
|
113
|
+
if (colon <= 0) {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
return { username: decoded.slice(0, colon), password: decoded.slice(colon + 1), serveraddress: server };
|
|
117
|
+
}
|
|
118
|
+
function readConfig(home) {
|
|
119
|
+
try {
|
|
120
|
+
return JSON.parse((0, node_fs_1.readFileSync)(path.join(home, 'config.json'), 'utf8'));
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* De inloggegevens voor de registry van deze image, of `null` als er niet is ingelogd.
|
|
128
|
+
*
|
|
129
|
+
* Dezelfde volgorde als de CLI: een helper voor precies deze registry (`credHelpers`), dan de
|
|
130
|
+
* algemene helper (`credsStore`), en pas zonder helper wat er in `auths` staat. Een helper die
|
|
131
|
+
* ontbreekt of faalt, geeft `null`: dan proberen we het anoniem, en zegt de registry wel of
|
|
132
|
+
* dat genoeg is. Een publieke image hoort niet te mislukken omdat een helper stuk is.
|
|
133
|
+
*/
|
|
134
|
+
async function credentialsFor(reference, home = (0, contexts_1.dockerHome)(), run = runHelper) {
|
|
135
|
+
const server = registryOf(reference);
|
|
136
|
+
const config = readConfig(home);
|
|
137
|
+
const helper = config.credHelpers?.[server] ?? config.credsStore;
|
|
138
|
+
if (isHelperName(helper)) {
|
|
139
|
+
try {
|
|
140
|
+
return parseHelperOutput(await run(helper, server), server);
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// "credentials not found" (niet ingelogd), een helper die er niet is, of een die faalt:
|
|
144
|
+
// in alle gevallen proberen we het anoniem.
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return fromConfigAuths(config, server);
|
|
149
|
+
}
|
|
150
|
+
//# sourceMappingURL=registry-auth.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry-auth.js","sourceRoot":"","sources":["../electron/registry-auth.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeReference = normalizeReference;
|
|
4
|
+
exports.selectStale = selectStale;
|
|
5
|
+
exports.toStaleContainers = toStaleContainers;
|
|
6
|
+
exports.findStale = findStale;
|
|
7
|
+
exports.listStaleContainers = listStaleContainers;
|
|
8
|
+
exports.renewContainers = renewContainers;
|
|
9
|
+
const compose_1 = require("./compose");
|
|
10
|
+
const docker_client_1 = require("./docker-client");
|
|
11
|
+
const images_1 = require("./images");
|
|
12
|
+
/**
|
|
13
|
+
* Na "Bijwerken" de containers ook vernieuwen.
|
|
14
|
+
*
|
|
15
|
+
* Een pull verplaatst alleen de tag. Een container die al draait, blijft op de image waarmee
|
|
16
|
+
* hij gemaakt is, tot hij opnieuw aangemaakt wordt. Voor een container uit een compose-project
|
|
17
|
+
* kan de app dat zelf doen: compose weet hoe de container eruit hoort te zien. Een losse
|
|
18
|
+
* container niet: daarvoor zou de app zijn hele configuratie moeten nabouwen, en wat er dan
|
|
19
|
+
* ontbreekt merk je pas als het misgaat.
|
|
20
|
+
*
|
|
21
|
+
* Welke containers het zijn, bepaalt main. De renderer stuurt alleen de tag mee; zo kan hij
|
|
22
|
+
* nooit een willekeurige service of map aan compose voeren.
|
|
23
|
+
*/
|
|
24
|
+
const COMPOSE_PROJECT = 'com.docker.compose.project';
|
|
25
|
+
const COMPOSE_SERVICE = 'com.docker.compose.service';
|
|
26
|
+
const COMPOSE_WORKING_DIR = 'com.docker.compose.project.working_dir';
|
|
27
|
+
const COMPOSE_CONFIG_FILES = 'com.docker.compose.project.config_files';
|
|
28
|
+
/**
|
|
29
|
+
* Een referentie in zijn volle vorm, zodat `mysql:8.4` en `docker.io/library/mysql:8.4` gelijk
|
|
30
|
+
* zijn, en `nginx` gelijk is aan `nginx:latest`. `null` bij een digest: een container die op
|
|
31
|
+
* een digest vastgepind is, verschuift niet mee met een tag.
|
|
32
|
+
*/
|
|
33
|
+
function normalizeReference(reference) {
|
|
34
|
+
if (reference.includes('@')) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const { repository, tag } = (0, images_1.splitReference)(reference);
|
|
38
|
+
const slash = repository.indexOf('/');
|
|
39
|
+
const first = slash === -1 ? '' : repository.slice(0, slash);
|
|
40
|
+
// Zoals Docker het zelf beslist: het eerste deel is een host als er een punt of poort in
|
|
41
|
+
// staat, of als het `localhost` is. Anders is het een naam op Docker Hub.
|
|
42
|
+
const hasHost = first.includes('.') || first.includes(':') || first === 'localhost';
|
|
43
|
+
const host = !hasHost || first === 'index.docker.io' ? 'docker.io' : first;
|
|
44
|
+
const path = hasHost ? repository.slice(slash + 1) : repository;
|
|
45
|
+
return `${host}/${host === 'docker.io' && !path.includes('/') ? `library/${path}` : path}:${tag}`;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* De containers die met deze tag gemaakt zijn, maar op een andere image draaien dan waar de
|
|
49
|
+
* tag nu naar wijst.
|
|
50
|
+
*
|
|
51
|
+
* Gegroepeerd per project én per plek: een project kan deels vanuit Windows en deels vanuit
|
|
52
|
+
* WSL gestart zijn, en elk deel hoort vernieuwd te worden vanaf de plek waar het vandaan kwam.
|
|
53
|
+
*/
|
|
54
|
+
function selectStale(reference, currentImageId, containers) {
|
|
55
|
+
const wanted = normalizeReference(reference);
|
|
56
|
+
const groups = new Map();
|
|
57
|
+
const loose = [];
|
|
58
|
+
if (wanted === null) {
|
|
59
|
+
return { groups: [], loose: [] };
|
|
60
|
+
}
|
|
61
|
+
for (const container of containers) {
|
|
62
|
+
if (container.imageId === currentImageId || normalizeReference(container.configImage) !== wanted) {
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
const project = container.labels[COMPOSE_PROJECT];
|
|
66
|
+
const service = container.labels[COMPOSE_SERVICE];
|
|
67
|
+
const workingDir = container.labels[COMPOSE_WORKING_DIR];
|
|
68
|
+
if (project === undefined || service === undefined || workingDir === undefined || workingDir === '') {
|
|
69
|
+
loose.push(container.name);
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const configFiles = container.labels[COMPOSE_CONFIG_FILES] ?? '';
|
|
73
|
+
const key = [project, workingDir, configFiles].join('\n');
|
|
74
|
+
const group = groups.get(key) ?? { project, location: { workingDir, configFiles: (0, compose_1.splitConfigFiles)(configFiles) }, services: new Set() };
|
|
75
|
+
group.services.add(service);
|
|
76
|
+
groups.set(key, group);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
groups: [...groups.values()].map((group) => ({ ...group, services: [...group.services].sort() })),
|
|
80
|
+
loose: loose.sort(),
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/** Wat de renderer te zien krijgt: per project de services, zonder paden. */
|
|
84
|
+
function toStaleContainers(set) {
|
|
85
|
+
const projects = new Map();
|
|
86
|
+
for (const group of set.groups) {
|
|
87
|
+
const services = projects.get(group.project) ?? new Set();
|
|
88
|
+
group.services.forEach((service) => services.add(service));
|
|
89
|
+
projects.set(group.project, services);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
projects: [...projects].map(([name, services]) => ({ name, services: [...services].sort() })),
|
|
93
|
+
loose: set.loose,
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
const dockerDeps = {
|
|
97
|
+
imageId: async (reference) => {
|
|
98
|
+
try {
|
|
99
|
+
const image = await (0, docker_client_1.getConnection)().docker.getImage(reference).inspect();
|
|
100
|
+
return image.Id;
|
|
101
|
+
}
|
|
102
|
+
catch {
|
|
103
|
+
return null;
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
running: async (currentImageId) => {
|
|
107
|
+
const { docker } = (0, docker_client_1.getConnection)();
|
|
108
|
+
const listed = await docker.listContainers();
|
|
109
|
+
// Alleen wie niet al op de nieuwe image draait, hoeft geïnspecteerd te worden: in de
|
|
110
|
+
// lijst staat bij `Image` het id in plaats van de naam zodra de tag verschoven is.
|
|
111
|
+
const candidates = listed.filter((container) => container.ImageID !== currentImageId);
|
|
112
|
+
const inspected = await Promise.all(candidates.map(async (container) => {
|
|
113
|
+
try {
|
|
114
|
+
const detail = await docker.getContainer(container.Id).inspect();
|
|
115
|
+
return {
|
|
116
|
+
name: detail.Name.replace(/^\//, ''),
|
|
117
|
+
imageId: detail.Image,
|
|
118
|
+
configImage: detail.Config.Image,
|
|
119
|
+
// Een container zonder labels heeft hier `null`, ondanks het type.
|
|
120
|
+
labels: detail.Config.Labels ?? {},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// Net verdwenen tussen de lijst en de inspect; dan valt er ook niets te vernieuwen.
|
|
125
|
+
return null;
|
|
126
|
+
}
|
|
127
|
+
}));
|
|
128
|
+
return inspected.filter((container) => container !== null);
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
/** De verouderde containers bij deze tag; niets als de tag er lokaal niet is of een digest is. */
|
|
132
|
+
async function findStale(reference, deps = dockerDeps) {
|
|
133
|
+
const currentImageId = await deps.imageId(reference);
|
|
134
|
+
if (currentImageId === null || normalizeReference(reference) === null) {
|
|
135
|
+
return { groups: [], loose: [] };
|
|
136
|
+
}
|
|
137
|
+
return selectStale(reference, currentImageId, await deps.running(currentImageId));
|
|
138
|
+
}
|
|
139
|
+
/** Voor de renderer: welke containers achterlopen, zonder paden. */
|
|
140
|
+
async function listStaleContainers(reference) {
|
|
141
|
+
return toStaleContainers(await findStale(reference));
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Maakt de verouderde compose-services opnieuw aan, één compose-aanroep per project en plek.
|
|
145
|
+
* Mislukt er één, dan gaan de andere door; de melding zegt welk project het was.
|
|
146
|
+
*/
|
|
147
|
+
async function renewContainers(reference, deps = dockerDeps, run = compose_1.runCompose) {
|
|
148
|
+
const { groups } = await findStale(reference, deps);
|
|
149
|
+
const renewed = [];
|
|
150
|
+
const problems = [];
|
|
151
|
+
for (const group of groups) {
|
|
152
|
+
const result = await run(group.location, (0, compose_1.buildRenewArgs)(group.project, group.location, group.services), 'up');
|
|
153
|
+
if (result.ok) {
|
|
154
|
+
renewed.push(...group.services);
|
|
155
|
+
}
|
|
156
|
+
else {
|
|
157
|
+
problems.push(`${group.project}: ${result.problem}`);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return { renewed, problems };
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=renew.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"renew.js","sourceRoot":"","sources":["../electron/renew.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RESTART_POLICIES = void 0;
|
|
4
|
+
exports.normalizePolicy = normalizePolicy;
|
|
5
|
+
exports.toRestartPolicy = toRestartPolicy;
|
|
6
|
+
exports.readRestartPolicy = readRestartPolicy;
|
|
7
|
+
exports.applyRestartPolicy = applyRestartPolicy;
|
|
8
|
+
const docker_client_1 = require("./docker-client");
|
|
9
|
+
/**
|
|
10
|
+
* De restart policy van een bestaande container aanpassen.
|
|
11
|
+
*
|
|
12
|
+
* `/containers/{id}/update` doet dit zonder de container opnieuw te maken, ook terwijl hij
|
|
13
|
+
* draait. Het startformulier laat de policy er bewust uit — ad hoc kies je hem zelden — maar
|
|
14
|
+
* achteraf alsnog op `unless-stopped` zetten was tot nu een gang naar de CLI.
|
|
15
|
+
*
|
|
16
|
+
* Verder gebruiken we `update` niet. Geheugen- en cpu-grenzen aanpassen op een draaiende
|
|
17
|
+
* container hangt af van de cgroup-opzet eronder, en een grens die stilletjes niets doet is
|
|
18
|
+
* erger dan geen knop.
|
|
19
|
+
*/
|
|
20
|
+
exports.RESTART_POLICIES = ['no', 'always', 'unless-stopped', 'on-failure'];
|
|
21
|
+
/** Docker weigert een maximum bij elk beleid behalve `on-failure`; bij de rest hoort het nul te zijn. */
|
|
22
|
+
function normalizePolicy(policy) {
|
|
23
|
+
if (policy.name !== 'on-failure') {
|
|
24
|
+
return { name: policy.name, maximumRetryCount: 0 };
|
|
25
|
+
}
|
|
26
|
+
return { name: 'on-failure', maximumRetryCount: Math.max(0, Math.trunc(policy.maximumRetryCount)) };
|
|
27
|
+
}
|
|
28
|
+
/** Wat inspect erover zegt. Een lege naam is Docker's manier om "geen beleid" te schrijven. */
|
|
29
|
+
function toRestartPolicy(raw) {
|
|
30
|
+
const name = exports.RESTART_POLICIES.find((known) => known === raw?.Name) ?? 'no';
|
|
31
|
+
return normalizePolicy({ name, maximumRetryCount: raw?.MaximumRetryCount ?? 0 });
|
|
32
|
+
}
|
|
33
|
+
/** Het huidige beleid van deze container. */
|
|
34
|
+
async function readRestartPolicy(id) {
|
|
35
|
+
try {
|
|
36
|
+
const { docker } = (0, docker_client_1.getConnection)();
|
|
37
|
+
const raw = (await docker.getContainer(id).inspect());
|
|
38
|
+
return { ok: true, policy: toRestartPolicy(raw.HostConfig?.RestartPolicy) };
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
41
|
+
return { ok: false, problem: (0, docker_client_1.readableError)(err, (0, docker_client_1.getConnection)().endpoint).message };
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/** Zet het beleid. Werkt ook op een draaiende container: Docker maakt hem er niet voor opnieuw. */
|
|
45
|
+
async function applyRestartPolicy(id, policy) {
|
|
46
|
+
try {
|
|
47
|
+
const { docker } = (0, docker_client_1.getConnection)();
|
|
48
|
+
const wanted = normalizePolicy(policy);
|
|
49
|
+
await docker.getContainer(id).update({
|
|
50
|
+
RestartPolicy: { Name: wanted.name, MaximumRetryCount: wanted.maximumRetryCount },
|
|
51
|
+
});
|
|
52
|
+
return { ok: true };
|
|
53
|
+
}
|
|
54
|
+
catch (err) {
|
|
55
|
+
return { ok: false, problem: (0, docker_client_1.readableError)(err, (0, docker_client_1.getConnection)().endpoint).message };
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=restart-policy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"restart-policy.js","sourceRoot":"","sources":["../electron/restart-policy.ts"],"names":[],"mappings":";;;AAkBA,0CAOC;AAGD,0CAKC;AAGD,8CAYC;AAGD,gDAcC;AAhED,mDAA+D;AAE/D;;;;;;;;;;GAUG;AAEU,QAAA,gBAAgB,GAAiC,CAAC,IAAI,EAAE,QAAQ,EAAE,gBAAgB,EAAE,YAAY,CAAC,CAAC;AAE/G,yGAAyG;AACzG,SAAgB,eAAe,CAAC,MAAqB;IAEnD,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;QACjC,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,iBAAiB,EAAE,CAAC,EAAE,CAAC;IACrD,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,YAAY,EAAE,iBAAiB,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC;AACtG,CAAC;AAED,+FAA+F;AAC/F,SAAgB,eAAe,CAAC,GAAgF;IAE9G,MAAM,IAAI,GAAG,wBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,GAAG,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC;IAE3E,OAAO,eAAe,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,GAAG,EAAE,iBAAiB,IAAI,CAAC,EAAE,CAAC,CAAC;AACnF,CAAC;AAED,6CAA6C;AACtC,KAAK,UAAU,iBAAiB,CAAC,EAAU;IAEhD,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,6BAAa,GAAE,CAAC;QACnC,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,CAEnD,CAAC;QAEF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,aAAa,CAAC,EAAE,CAAC;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAA,6BAAa,EAAC,GAAG,EAAE,IAAA,6BAAa,GAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;IACtF,CAAC;AACH,CAAC;AAED,mGAAmG;AAC5F,KAAK,UAAU,kBAAkB,CAAC,EAAU,EAAE,MAAqB;IAExE,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,IAAA,6BAAa,GAAE,CAAC;QACnC,MAAM,MAAM,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;QAEvC,MAAM,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC;YACnC,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE;SAClF,CAAC,CAAC;QAEH,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,IAAA,6BAAa,EAAC,GAAG,EAAE,IAAA,6BAAa,GAAE,CAAC,QAAQ,CAAC,CAAC,OAAO,EAAE,CAAC;IACtF,CAAC;AACH,CAAC"}
|