epaperclip 0.0.0-stage → 1.0.0-rc3

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 OpenSourcx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,24 @@
1
- # Temporary Holding Version
1
+ # epaperclip
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Installs [ePaperclip](https://github.com/OpenSourcx/papercliped-engine) on a Proxmox VE host: a console on port 443 that people sign in to with their Proxmox accounts, and its engine (Paperclip) as a locked-down service on loopback. Proxmox's own web interface on port 8006 is never changed.
4
+
5
+ In the Proxmox host's shell, as root:
6
+
7
+ ```sh
8
+ npx epaperclip install
9
+ ```
10
+
11
+ or `npm install -g epaperclip`, then `epaperclip install`.
12
+
13
+ | Command | Does |
14
+ | --- | --- |
15
+ | `epaperclip install` | install, or upgrade to this package's version |
16
+ | `epaperclip status` | version, whether both services run and answer, where the data is |
17
+ | `epaperclip rollback` | go back to the previous version |
18
+ | `epaperclip uninstall` | remove it, keeping data and settings (`--purge` removes those too) |
19
+
20
+ This package carries the signed release (the tarball, its manifest and Ed25519 signature) and the project's public key. The command verifies the signature and the checksum and refuses to unpack anything that doesn't match. A release candidate is on the `next` tag (`npx epaperclip@next install`). It carries the same installer as the release download and the Debian package. It checks the host first and changes nothing if something is missing. It brings its own pinned, checksum-verified Node.js and installs the engine from its lockfile, so it needs internet access. It test-starts everything and rolls back by itself if the new version doesn't come up. Node.js on the host is only used to start this command.
21
+
22
+ Requirements: Proxmox VE 8 or newer, 4 GB of memory recommended (2 GB minimum), about 3 GB of free disk. Full guide: [docs/INSTALL.md](https://github.com/OpenSourcx/papercliped-engine/blob/main/docs/INSTALL.md).
23
+
24
+ MIT licensed.
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+ // epaperclip install | status | rollback | uninstall [--purge]
3
+ // Verifies the signed release this package carries (payload/epaperclip.tar.gz, its manifest and Ed25519 signature, against
4
+ // the public key pinned beside them), unpacks it to a private temporary folder and runs the installer inside (the same one
5
+ // as the release download and the Debian package). It must run as root on a Proxmox VE host. Nothing is unpacked or run
6
+ // unless the signature, the manifest's SHA-256 and its version all check out. Node.js is only needed to start this command: the
7
+ // installer brings its own pinned, checksum-verified Node.js for the services.
8
+ import { spawnSync } from "node:child_process";
9
+ import { createHash, createPublicKey, verify } from "node:crypto";
10
+ import { accessSync, constants, mkdtempSync, readFileSync, rmSync } from "node:fs";
11
+ import { tmpdir } from "node:os";
12
+ import { delimiter, join } from "node:path";
13
+
14
+ const payload = new URL("../payload/", import.meta.url).pathname;
15
+ const usage = `usage: epaperclip <command>
16
+
17
+ install install ePaperclip, or upgrade it to this package's version
18
+ status version, whether both services run and answer, where the data is
19
+ rollback go back to the previous version
20
+ uninstall [--purge] remove it (keeps data and settings; --purge removes those too)
21
+
22
+ Run as root in the Proxmox host's shell, for example: sudo npx epaperclip install
23
+ Guide: https://github.com/OpenSourcx/papercliped-engine/blob/main/docs/INSTALL.md`;
24
+
25
+ const fail = (msg, code = 1) => { console.error(`epaperclip: ${msg}`); process.exit(code); };
26
+ const [cmd, ...rest] = process.argv.slice(2);
27
+ if (!cmd || cmd === "help" || cmd === "--help" || cmd === "-h") { console.log(usage); process.exit(cmd ? 0 : 2); }
28
+ if (cmd === "--version" || cmd === "-v" || cmd === "version") {
29
+ try { console.log(JSON.parse(readFileSync(join(payload, "epaperclip.manifest.json"), "utf8")).version); } catch { console.log("unknown"); }
30
+ process.exit(0);
31
+ }
32
+
33
+ const flags = { install: [], status: ["--status"], rollback: ["--rollback"], uninstall: ["--uninstall"] }[cmd];
34
+ if (!flags) fail(`unknown command '${cmd}'\n\n${usage}`, 2);
35
+ let args = [...flags, ...rest];
36
+ if (cmd === "uninstall" && rest.includes("--purge")) args = ["--purge", ...rest.filter((a) => a !== "--purge")];
37
+
38
+ const onPath = (name) => (process.env.PATH ?? "").split(delimiter).concat("/usr/bin", "/usr/sbin").some((d) => {
39
+ try { accessSync(join(d, name), constants.X_OK); return true; } catch { return false; }
40
+ });
41
+ if (process.platform !== "linux") fail("ePaperclip installs on a Proxmox VE host (Linux); this is " + process.platform);
42
+ if (typeof process.getuid === "function" && process.getuid() !== 0) fail(`run as root, for example: sudo npx epaperclip ${[cmd, ...rest].join(" ")}`);
43
+ if (!onPath("pveversion")) fail("this isn't a Proxmox VE host (pveversion wasn't found). Run it in the Proxmox host's own shell.");
44
+
45
+ // Fail closed: the signature over the manifest, then the manifest's SHA-256 and file name against the tarball.
46
+ const read = (f) => { try { return readFileSync(join(payload, f)); } catch { return null; } };
47
+ const [tarball, manifest, signature, key] = ["epaperclip.tar.gz", "epaperclip.manifest.json", "epaperclip.manifest.sig", "release-signing.pub"].map(read);
48
+ if (!key) fail("this package carries no release-signing key, so nothing can be verified and nothing was installed. The maintainer must run scripts/release-keygen.mjs and publish a package built with deploy/release-signing.pub");
49
+ if (!tarball || !manifest || !signature) fail("this package is incomplete or unsigned (the release, its manifest or its signature is missing), so nothing was installed; reinstall the package");
50
+ let signed = false;
51
+ try { signed = verify(null, manifest, createPublicKey(key), Buffer.from(signature.toString("utf8").replace(/\s+/g, ""), "base64")); } catch { /* not valid */ }
52
+ if (!signed) fail("the release's signature is not valid for the pinned key, so nothing was installed (the package was not signed by the project, or was altered)");
53
+ let m;
54
+ try { m = JSON.parse(manifest.toString("utf8")); } catch { fail("the signed manifest can't be read, so nothing was installed"); }
55
+ if (m.name !== "epaperclip.tar.gz" || !/^[0-9a-f]{64}$/.test(m.sha256 ?? "") || !/^[0-9]{1,6}\.[0-9]{1,6}\.[0-9]{1,6}(-[0-9A-Za-z.]{1,40})?$/.test(m.version ?? "")) fail("the signed manifest is not for this release file, so nothing was installed");
56
+ if (createHash("sha256").update(tarball).digest("hex") !== m.sha256 || (typeof m.size === "number" && m.size !== tarball.length)) fail("the release in this package doesn't match its signed checksum, so nothing was installed");
57
+
58
+ const work = mkdtempSync(join(tmpdir(), "epaperclip-npm-"));
59
+ const cleanup = () => rmSync(work, { recursive: true, force: true });
60
+ const x = spawnSync("tar", ["-xzf", join(payload, "epaperclip.tar.gz"), "--no-same-owner", "-C", work], { stdio: "inherit" });
61
+ if (x.error || x.status !== 0) { cleanup(); fail("couldn't unpack the release"); }
62
+ const installer = join(work, "epaperclip", "deploy", "install.sh");
63
+ try { accessSync(installer, constants.R_OK); } catch { cleanup(); fail("the release is incomplete (deploy/install.sh is missing)"); }
64
+ const r = spawnSync("bash", [installer, ...args], { stdio: "inherit" });
65
+ cleanup();
66
+ if (r.error) fail(`couldn't run the installer: ${r.error.message}`);
67
+ process.exit(r.status ?? 1);
package/package.json CHANGED
@@ -1,6 +1,39 @@
1
1
  {
2
2
  "name": "epaperclip",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "1.0.0-rc3",
4
+ "description": "Install ePaperclip on a Proxmox VE host: the console on port 443, signed in with Proxmox accounts, and its engine on loopback.",
5
+ "license": "MIT",
6
+ "author": "OpenSourcx",
7
+ "homepage": "https://github.com/OpenSourcx/papercliped-engine/blob/main/docs/INSTALL.md",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/OpenSourcx/papercliped-engine.git",
11
+ "directory": "npm/epaperclip"
12
+ },
13
+ "keywords": [
14
+ "proxmox",
15
+ "pve",
16
+ "paperclip",
17
+ "agents",
18
+ "installer"
19
+ ],
20
+ "type": "module",
21
+ "bin": {
22
+ "epaperclip": "bin/epaperclip.js"
23
+ },
24
+ "files": [
25
+ "bin/epaperclip.js",
26
+ "payload/",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "os": [
31
+ "linux"
32
+ ],
33
+ "engines": {
34
+ "node": ">=18"
35
+ },
36
+ "scripts": {
37
+ "prepack": "node scripts/prepack.mjs"
38
+ }
39
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "format": 1,
3
+ "name": "epaperclip.tar.gz",
4
+ "version": "1.0.0-rc3",
5
+ "sha256": "a7dbd2ed0adac74a5cc7406c38ef69e94306a0c86fcf5b844b766f6f75204cf0",
6
+ "size": 1609280
7
+ }
@@ -0,0 +1 @@
1
+ 7/VouQPeIevNM11nEuO/uOFbsyniaJ+36Y+2JMcYIukGdND3Fd8G667MJMQ4I7fH6+EQ2U755qZwCD2mJLA4Cw==
Binary file
@@ -0,0 +1,3 @@
1
+ -----BEGIN PUBLIC KEY-----
2
+ MCowBQYDK2VwAyEAUKvQFShqx/jCwgZZn+6ereMKFhDKzDGcr5lut7r2sds=
3
+ -----END PUBLIC KEY-----