@twinsearth/w2m-dsh-plugin 0.6.2 → 0.8.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/CHANGELOG.md +1057 -0
- package/README.md +9 -2
- package/bin/w2m-localside.mjs +0 -0
- package/bin/w2m-rabbit.mjs +6 -0
- package/bin/w2m-stun.mjs +0 -0
- package/deploy/server/README.md +109 -0
- package/deploy/server/deploy-w2m.sh +161 -0
- package/deploy/server/w2m-localside.service +31 -0
- package/deploy/server/w2m-rabbit.service +26 -0
- package/deploy/server/w2m-stun.service +26 -0
- package/docs/ACCOUNT-FLEET-DESIGN.md +369 -0
- package/package.json +33 -22
- package/src/chatops/account.mjs +361 -0
- package/src/chatops/actions.mjs +227 -0
- package/src/chatops/approval-broker.mjs +320 -0
- package/src/chatops/auth.mjs +376 -0
- package/src/chatops/bridge.mjs +344 -0
- package/src/chatops/channel.mjs +192 -0
- package/src/chatops/commands.mjs +409 -0
- package/src/chatops/config-route.mjs +332 -0
- package/src/chatops/device-signing.mjs +218 -0
- package/src/chatops/durability.mjs +202 -0
- package/src/chatops/file-safety.mjs +282 -0
- package/src/chatops/fleet-scope.mjs +176 -0
- package/src/chatops/fleet-wiring.mjs +199 -0
- package/src/chatops/fleet.mjs +272 -0
- package/src/chatops/handoff.mjs +258 -0
- package/src/chatops/ilink-protocol.mjs +165 -0
- package/src/chatops/ilink-transport.mjs +168 -0
- package/src/chatops/ilink.mjs +423 -0
- package/src/chatops/index.mjs +429 -0
- package/src/chatops/outbound-queue.mjs +282 -0
- package/src/chatops/policy.mjs +356 -0
- package/src/chatops/run-command.mjs +308 -0
- package/src/plugin/tools.mjs +1 -1
- package/src/relay/server.mjs +96 -0
- package/src/relay/state.mjs +2233 -2011
package/README.md
CHANGED
|
@@ -250,7 +250,7 @@ dsh plugin --profile <profile-name> add @twinsearth/w2m-dsh-plugin
|
|
|
250
250
|
|
|
251
251
|
```bash
|
|
252
252
|
dsh plugin --profile <profile-name> add \
|
|
253
|
-
https://github.com/TwinsEarth/dsh-windows2macos/releases/download/v0.
|
|
253
|
+
https://github.com/TwinsEarth/dsh-windows2macos/releases/download/v0.6.3/twinsearth-w2m-dsh-plugin-0.6.3.tgz
|
|
254
254
|
```
|
|
255
255
|
|
|
256
256
|
**From the repository** — the form a marketplace's one-click installer uses (it clones
|
|
@@ -624,6 +624,13 @@ move with it: `claims` is 19 tests here and **22 when `dist/` holds a packed tar
|
|
|
624
624
|
its two tarball-vs-`package.json` checks run instead of skipping — so a checkout with `dist/` measures
|
|
625
625
|
**1,142 tests / 1,134 pass / 4 skip**, and that is the number to expect from a release tree.
|
|
626
626
|
|
|
627
|
+
> **These counts are the v0.5.9 measurement and have not been re-taken since.** They are kept, dated
|
|
628
|
+
> and attributed rather than refreshed, because a figure presented as current without having been
|
|
629
|
+
> measured is the failure this project's own rules exist to prevent. Suites added after v0.5.9 —
|
|
630
|
+
> `p2p-crypto`, and from v0.7.0 `chatops-approval` and `chatops-policy` — are therefore **not** in
|
|
631
|
+
> any total on this page. Treat every count below as a v0.5.9 measurement until a release re-runs
|
|
632
|
+
> the suite on its own host and says so.
|
|
633
|
+
|
|
627
634
|
**Which script runs which suite matters, because they are not the same set:**
|
|
628
635
|
|
|
629
636
|
| Command | Suites | Result on this host (v0.5.9) |
|
|
@@ -810,7 +817,7 @@ node bin/w2m-localside.mjs --rabbit http://<中继地址>:8787 --pair PAIR-XXXXX
|
|
|
810
817
|
|
|
811
818
|
# 3) 装 DSH 插件
|
|
812
819
|
dsh plugin --profile <profile-name> add \
|
|
813
|
-
https://github.com/TwinsEarth/dsh-windows2macos/releases/download/v0.
|
|
820
|
+
https://github.com/TwinsEarth/dsh-windows2macos/releases/download/v0.6.3/twinsearth-w2m-dsh-plugin-0.6.3.tgz
|
|
814
821
|
```
|
|
815
822
|
|
|
816
823
|
然后在 profile 的 `cordis.patch.yml` 里给插件 `rabbitUrl`(留空即用共享服务器)与 `operatorToken`,重启 DSH,即可直接用自然语言指挥:
|
package/bin/w2m-localside.mjs
CHANGED
|
File without changes
|
package/bin/w2m-rabbit.mjs
CHANGED
|
@@ -53,6 +53,9 @@ Credentials and state:
|
|
|
53
53
|
--no-persist Keep everything in memory; forget devices and tasks on
|
|
54
54
|
restart.
|
|
55
55
|
--pairing-code <c> Use a fixed pairing code instead of a generated one.
|
|
56
|
+
--fleet <id> Bind this relay to one account's fleet. Omitted, the relay serves
|
|
57
|
+
every device (the pre-v0.7.7 behaviour). Set, a device with no
|
|
58
|
+
fleet reaches nothing and a device in another fleet is invisible.
|
|
56
59
|
|
|
57
60
|
Request signing (v0.3.0):
|
|
58
61
|
--signing-secret <s> Shared secret for HMAC-signed requests. Unset means the relay does
|
|
@@ -98,6 +101,9 @@ try {
|
|
|
98
101
|
port: { type: 'string' },
|
|
99
102
|
state: { type: 'string' },
|
|
100
103
|
'pairing-code': { type: 'string' },
|
|
104
|
+
// v0.7.7: bind this relay to a fleet. Omitted means every device, which is the
|
|
105
|
+
// pre-v0.7.7 behaviour and therefore the migration-safe default.
|
|
106
|
+
fleet: { type: 'string' },
|
|
101
107
|
'heartbeat-ms': { type: 'string' },
|
|
102
108
|
'grace-ms': { type: 'string' },
|
|
103
109
|
'base-path': { type: 'string' },
|
package/bin/w2m-stun.mjs
CHANGED
|
File without changes
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
# Running the relay on a server
|
|
2
|
+
|
|
3
|
+
These are the units the shared relay **actually runs**, copied from
|
|
4
|
+
`/etc/systemd/system/` on the live host rather than written from the documentation. They are in the
|
|
5
|
+
repository because "how the server runs" is part of the thing being open-sourced — and because a
|
|
6
|
+
unit that exists only on one machine is a unit nobody can review, reproduce, or audit.
|
|
7
|
+
|
|
8
|
+
## The three services
|
|
9
|
+
|
|
10
|
+
| Unit | What it is | Port |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| `w2m-rabbit.service` | The relay: P2P rendezvous, signalling, and the task ledger | 8787 |
|
|
13
|
+
| `w2m-stun.service` | STUN responder, for reflexive address discovery during hole punching | 3478 |
|
|
14
|
+
| `w2m-localside.service` | A Localside agent, so the server is itself a fleet machine | — |
|
|
15
|
+
|
|
16
|
+
`w2m-localside` is deliberately the same agent every other machine runs. The server is not
|
|
17
|
+
privileged in the fleet's protocol — it is a peer that happens to be reachable — and running it
|
|
18
|
+
through the normal agent is what keeps that true.
|
|
19
|
+
|
|
20
|
+
## ⚠️ What is NOT here, and why
|
|
21
|
+
|
|
22
|
+
**`/var/lib/w2m/rabbit/` is not in this repository and must never be.**
|
|
23
|
+
|
|
24
|
+
It holds:
|
|
25
|
+
|
|
26
|
+
| File | Why it must not be published |
|
|
27
|
+
|---|---|
|
|
28
|
+
| `operator-token.txt` | **Full control of the fleet.** Anyone holding it can dispatch any allowed command to every machine. |
|
|
29
|
+
| `ledger` | The task history: every command run, on which machine, with which results. |
|
|
30
|
+
|
|
31
|
+
Two mechanisms keep this true, because one is not enough:
|
|
32
|
+
|
|
33
|
+
1. **`.gitignore`** refuses the paths, so an accidental `git add -A` cannot stage them.
|
|
34
|
+
2. **`scripts/scan-for-secrets.mjs`** reads the **content** of every tracked file and fails the
|
|
35
|
+
release on a credential shape. A `.gitignore` refuses a *path*; the ways a credential actually
|
|
36
|
+
escapes are pasting one into a source file, a fixture, or an example — so tracked content is
|
|
37
|
+
what gets read.
|
|
38
|
+
|
|
39
|
+
Run it before a release:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
node scripts/scan-for-secrets.mjs .
|
|
43
|
+
# 0 blocking, N for review -> exit 0
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
`REVIEW` findings (long hex strings, high-entropy assignments) are **not fatal by design**: a
|
|
47
|
+
scanner whose false positives block releases is a scanner someone deletes. Only real credential
|
|
48
|
+
shapes stop anything.
|
|
49
|
+
|
|
50
|
+
## Installing
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 1. A user that owns the state and nothing else.
|
|
54
|
+
sudo useradd --system --home /var/lib/w2m --shell /usr/sbin/nologin w2m
|
|
55
|
+
|
|
56
|
+
# 2. The paths the units reference.
|
|
57
|
+
sudo install -d -o w2m -g w2m /opt/w2m /var/lib/w2m /var/log/w2m
|
|
58
|
+
|
|
59
|
+
# 3. The code, at the tag being deployed.
|
|
60
|
+
sudo -u w2m git clone https://github.com/TwinsEarth/dsh-windows2macos /opt/w2m/app
|
|
61
|
+
sudo -u w2m git -C /opt/w2m/app checkout v0.7.10
|
|
62
|
+
|
|
63
|
+
# 4. The units.
|
|
64
|
+
sudo cp deploy/server/*.service /etc/systemd/system/
|
|
65
|
+
sudo systemctl daemon-reload
|
|
66
|
+
sudo systemctl enable --now w2m-rabbit w2m-stun
|
|
67
|
+
|
|
68
|
+
# 5. Pair the server as a fleet machine, then enable the agent.
|
|
69
|
+
sudo systemctl enable --now w2m-localside
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Notes on the hardening, since it is easy to weaken by accident
|
|
73
|
+
|
|
74
|
+
Every unit sets `NoNewPrivileges`, `PrivateTmp`, `ProtectHome`, and a `ProtectSystem` level, and
|
|
75
|
+
writes only inside `/var/lib/w2m` via `ReadWritePaths`. That last one matters: `ProtectSystem=full`
|
|
76
|
+
makes `/usr` and `/boot` read-only, so an agent that tried to write anywhere else would fail
|
|
77
|
+
loudly rather than silently succeed on a machine that should not be writable.
|
|
78
|
+
|
|
79
|
+
`w2m-stun` is stricter (`ProtectSystem=strict`, `RestrictAddressFamilies=AF_INET AF_INET6`) because
|
|
80
|
+
it needs a socket and nothing else.
|
|
81
|
+
|
|
82
|
+
**If you add a capability to an agent, check `ReadWritePaths` first.** The failure is a permission
|
|
83
|
+
error at runtime, which looks like a bug in the agent rather than a hardening setting.
|
|
84
|
+
|
|
85
|
+
## The `--fleet` flag, and why it is absent here
|
|
86
|
+
|
|
87
|
+
`w2m-rabbit` accepts `--fleet <account code>`, which binds the relay to one account's fleet. It is
|
|
88
|
+
**absent from this unit on purpose**, and the relay therefore runs unscoped: every paired device
|
|
89
|
+
reaches every other.
|
|
90
|
+
|
|
91
|
+
Turning it on is not a configuration change — it is a **fleet migration**:
|
|
92
|
+
|
|
93
|
+
1. the account code must be read on a machine that is **signed in** (a headless server cannot
|
|
94
|
+
produce one; it has no DeepSeek account),
|
|
95
|
+
2. the relay restarts scoped,
|
|
96
|
+
3. **every device must be re-paired**, because a device receives its fleet *from the pairing code*,
|
|
97
|
+
and on a scoped relay a device with no fleet reaches **nothing**.
|
|
98
|
+
|
|
99
|
+
Step 3 is the risk: the fleet goes silent until each machine is re-paired. That is the intended
|
|
100
|
+
fail-safe direction and it is still an outage while it lasts.
|
|
101
|
+
|
|
102
|
+
## Deliberately not included
|
|
103
|
+
|
|
104
|
+
* **TLS termination.** The live relay is behind a proxy that handles it; `--base-path` and
|
|
105
|
+
`--trust-proxy` exist for that arrangement and the certificate is the operator's business.
|
|
106
|
+
* **Backups.** The state directory is small (about 1 MB) and is the operator's to schedule. The
|
|
107
|
+
deployment script below does back it up before a swap, which is not the same as a backup policy.
|
|
108
|
+
* **Log rotation.** `StandardOutput=append:` grows without bound; the live host rotates
|
|
109
|
+
`/var/log/w2m/*.log` outside these units.
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
#
|
|
3
|
+
# Deploy one release tarball to a running relay, with a rollback that is automatic rather than
|
|
4
|
+
# remembered.
|
|
5
|
+
#
|
|
6
|
+
# This is the script the live server was updated with (v0.6.3 -> v0.7.7 -> v0.7.10). It is in the
|
|
7
|
+
# repository because a deployment that exists only in someone's shell history is a deployment nobody
|
|
8
|
+
# can review — and because the order of these steps is the whole safety argument:
|
|
9
|
+
#
|
|
10
|
+
# 1. verify the checksum BEFORE unpacking, so a truncated upload cannot become a running service
|
|
11
|
+
# 2. back up the tree in place, so rollback does not depend on the network
|
|
12
|
+
# 3. stage and check for entry points BEFORE swapping, so a bad tarball never reaches the
|
|
13
|
+
# live path
|
|
14
|
+
# 4. restart and health-check, and roll back automatically if the health check fails
|
|
15
|
+
#
|
|
16
|
+
# Step 3 is the one that matters most: `git archive` of a wrong subdirectory produces a tarball that
|
|
17
|
+
# unpacks cleanly and contains no `bin/`, and without the entry-point check that becomes a service
|
|
18
|
+
# that starts, finds nothing to run, and reports a confusing error.
|
|
19
|
+
#
|
|
20
|
+
# Usage: deploy-w2m.sh <tarball> <expected-sha256> [--fleet <account-code>]
|
|
21
|
+
#
|
|
22
|
+
set -euo pipefail
|
|
23
|
+
|
|
24
|
+
APP_DIR=/opt/w2m/app
|
|
25
|
+
BACKUP_ROOT=/opt/w2m
|
|
26
|
+
STATE_DIR=/var/lib/w2m
|
|
27
|
+
SERVICES=(w2m-rabbit w2m-stun w2m-localside)
|
|
28
|
+
STAMP=$(date -u +%Y%m%dT%H%M%SZ)
|
|
29
|
+
|
|
30
|
+
TARBALL="${1:-}"
|
|
31
|
+
EXPECTED="${2:-}"
|
|
32
|
+
FLEET=""
|
|
33
|
+
if [ "${3:-}" = "--fleet" ]; then FLEET="${4:-}"; fi
|
|
34
|
+
|
|
35
|
+
if [ -z "$TARBALL" ] || [ -z "$EXPECTED" ]; then
|
|
36
|
+
echo "usage: $0 <tarball> <expected-sha256> [--fleet <account-code>]" >&2
|
|
37
|
+
exit 2
|
|
38
|
+
fi
|
|
39
|
+
if [ ! -f "$TARBALL" ]; then echo "no such tarball: $TARBALL" >&2; exit 2; fi
|
|
40
|
+
|
|
41
|
+
echo "=== 1. verify the artefact ==="
|
|
42
|
+
ACTUAL=$(sha256sum "$TARBALL" | awk '{print $1}')
|
|
43
|
+
echo " expected $EXPECTED"
|
|
44
|
+
echo " actual $ACTUAL"
|
|
45
|
+
if [ "$ACTUAL" != "$EXPECTED" ]; then
|
|
46
|
+
echo " CHECKSUM MISMATCH -- refusing to deploy. A truncated upload must never become a service." >&2
|
|
47
|
+
exit 1
|
|
48
|
+
fi
|
|
49
|
+
echo " checksum OK"
|
|
50
|
+
|
|
51
|
+
echo
|
|
52
|
+
echo "=== 2. what is running now ==="
|
|
53
|
+
if [ -f "$APP_DIR/package.json" ]; then
|
|
54
|
+
echo " $APP_DIR is version $(node -e "process.stdout.write(require('$APP_DIR/package.json').version)")"
|
|
55
|
+
else
|
|
56
|
+
echo " $APP_DIR has no package.json (first deploy?)"
|
|
57
|
+
fi
|
|
58
|
+
for s in "${SERVICES[@]}"; do
|
|
59
|
+
printf ' %-16s %s\n' "$s" "$(systemctl is-active "$s" 2>/dev/null || echo inactive)"
|
|
60
|
+
done
|
|
61
|
+
|
|
62
|
+
echo
|
|
63
|
+
echo "=== 3. back up the current tree ==="
|
|
64
|
+
BACKUP="$BACKUP_ROOT/backup-$STAMP"
|
|
65
|
+
if [ -d "$APP_DIR" ]; then
|
|
66
|
+
cp -a "$APP_DIR" "$BACKUP"
|
|
67
|
+
echo " $APP_DIR -> $BACKUP"
|
|
68
|
+
else
|
|
69
|
+
echo " nothing to back up"
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo
|
|
73
|
+
echo "=== 4. unpack to staging and check it ==="
|
|
74
|
+
STAGING=$(mktemp -d)
|
|
75
|
+
trap 'rm -rf "$STAGING"' EXIT
|
|
76
|
+
tar -xzf "$TARBALL" -C "$STAGING"
|
|
77
|
+
# The tarball contains a single `package/` root, by npm convention.
|
|
78
|
+
SRC="$STAGING/package"
|
|
79
|
+
if [ ! -d "$SRC" ]; then SRC="$STAGING"; fi
|
|
80
|
+
|
|
81
|
+
STAGED_VERSION=$(node -e "process.stdout.write(require('$SRC/package.json').version)" 2>/dev/null || echo "?")
|
|
82
|
+
echo " staged version: $STAGED_VERSION"
|
|
83
|
+
|
|
84
|
+
# The check that turns a confusing runtime failure into a clear deployment failure.
|
|
85
|
+
MISSING=""
|
|
86
|
+
for f in bin/w2m-rabbit.mjs bin/w2m-stun.mjs bin/w2m-localside.mjs package.json; do
|
|
87
|
+
[ -e "$SRC/$f" ] || MISSING="$MISSING $f"
|
|
88
|
+
done
|
|
89
|
+
if [ -n "$MISSING" ]; then
|
|
90
|
+
echo " MISSING ENTRY POINTS:$MISSING" >&2
|
|
91
|
+
echo " refusing to swap: this tarball would install a service that cannot start." >&2
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
echo " entry points present"
|
|
95
|
+
|
|
96
|
+
echo
|
|
97
|
+
echo "=== 5. swap into place ==="
|
|
98
|
+
rm -rf "$APP_DIR.old"
|
|
99
|
+
if [ -d "$APP_DIR" ]; then mv "$APP_DIR" "$APP_DIR.old"; fi
|
|
100
|
+
cp -a "$SRC" "$APP_DIR"
|
|
101
|
+
chown -R w2m:w2m "$APP_DIR" 2>/dev/null || true
|
|
102
|
+
echo " swapped; previous tree kept at $APP_DIR.old"
|
|
103
|
+
|
|
104
|
+
echo
|
|
105
|
+
echo "=== 6. restart ==="
|
|
106
|
+
# The relay's fleet binding: omitted means unscoped, which is the pre-v0.7.8 behaviour.
|
|
107
|
+
if [ -n "$FLEET" ]; then
|
|
108
|
+
echo " --fleet $FLEET requested"
|
|
109
|
+
if grep -q -- '--fleet' /etc/systemd/system/w2m-rabbit.service; then
|
|
110
|
+
sed -i "s|--fleet [^ ]*|--fleet $FLEET|" /etc/systemd/system/w2m-rabbit.service
|
|
111
|
+
else
|
|
112
|
+
sed -i "s|\(--state [^ ]*\)|\1 --fleet $FLEET|" /etc/systemd/system/w2m-rabbit.service
|
|
113
|
+
fi
|
|
114
|
+
systemctl daemon-reload
|
|
115
|
+
echo " WARNING: the relay is now scoped. A device with no fleet reaches NOTHING."
|
|
116
|
+
echo " Every device must be re-paired with a code issued by this relay."
|
|
117
|
+
fi
|
|
118
|
+
systemctl restart "${SERVICES[@]}"
|
|
119
|
+
|
|
120
|
+
echo
|
|
121
|
+
echo "=== 7. health check ==="
|
|
122
|
+
sleep 4
|
|
123
|
+
HEALTHY=1
|
|
124
|
+
for s in "${SERVICES[@]}"; do
|
|
125
|
+
STATE=$(systemctl is-active "$s" 2>/dev/null || echo inactive)
|
|
126
|
+
printf ' %-16s %s\n' "$s" "$STATE"
|
|
127
|
+
[ "$STATE" = "active" ] || HEALTHY=0
|
|
128
|
+
done
|
|
129
|
+
|
|
130
|
+
if command -v curl >/dev/null 2>&1; then
|
|
131
|
+
HEALTH=$(curl -fsS --max-time 10 http://127.0.0.1:8787/healthz 2>/dev/null || echo "")
|
|
132
|
+
if [ -n "$HEALTH" ]; then
|
|
133
|
+
echo " healthz: $HEALTH"
|
|
134
|
+
else
|
|
135
|
+
echo " healthz: NO ANSWER"
|
|
136
|
+
HEALTHY=0
|
|
137
|
+
fi
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
if [ "$HEALTHY" != "1" ]; then
|
|
141
|
+
echo
|
|
142
|
+
echo "=== 8. ROLLBACK ==="
|
|
143
|
+
if [ -d "$BACKUP" ]; then
|
|
144
|
+
rm -rf "$APP_DIR"
|
|
145
|
+
mv "$BACKUP" "$APP_DIR"
|
|
146
|
+
systemctl restart "${SERVICES[@]}"
|
|
147
|
+
echo " rolled back to the previous tree and restarted" >&2
|
|
148
|
+
else
|
|
149
|
+
echo " no backup to roll back to" >&2
|
|
150
|
+
fi
|
|
151
|
+
exit 1
|
|
152
|
+
fi
|
|
153
|
+
|
|
154
|
+
echo
|
|
155
|
+
echo "=== deployed ==="
|
|
156
|
+
echo " version: $STAGED_VERSION"
|
|
157
|
+
echo " backup: $BACKUP"
|
|
158
|
+
echo " previous: $APP_DIR.old (removable once this is proven)"
|
|
159
|
+
echo
|
|
160
|
+
echo " NOTE: relay state lives in $STATE_DIR and was NOT touched by this script."
|
|
161
|
+
echo " The ledger and the operator token survive a deploy; that is deliberate."
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=W2M Localside agent (shared server as a fleet machine)
|
|
3
|
+
After=network-online.target w2m-rabbit.service
|
|
4
|
+
Wants=network-online.target
|
|
5
|
+
Wants=w2m-rabbit.service
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=w2m
|
|
10
|
+
Group=w2m
|
|
11
|
+
WorkingDirectory=/opt/w2m/demo
|
|
12
|
+
ExecStart=/usr/local/bin/node /opt/w2m/app/bin/w2m-localside.mjs \
|
|
13
|
+
--rabbit http://127.0.0.1:8787 \
|
|
14
|
+
--project /opt/w2m/shared \
|
|
15
|
+
--name jp-shared \
|
|
16
|
+
--state /var/lib/w2m/localside-jp \
|
|
17
|
+
--p2p-mode auto \
|
|
18
|
+
--p2p-port 41234 \
|
|
19
|
+
--allowed-commands '["node --version","node --test","node -e","git status --porcelain","git rev-parse","git log","git diff","npm test","npm run"]'
|
|
20
|
+
Restart=always
|
|
21
|
+
RestartSec=3
|
|
22
|
+
NoNewPrivileges=true
|
|
23
|
+
PrivateTmp=true
|
|
24
|
+
ProtectSystem=full
|
|
25
|
+
ProtectHome=true
|
|
26
|
+
ReadWritePaths=/var/lib/w2m
|
|
27
|
+
StandardOutput=append:/var/log/w2m/localside.log
|
|
28
|
+
StandardError=append:/var/log/w2m/localside.log
|
|
29
|
+
|
|
30
|
+
[Install]
|
|
31
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=W2M Rabbit relay (P2P rendezvous, signalling and task ledger)
|
|
3
|
+
Documentation=https://github.com/TwinsEarth/dsh-windows2macos
|
|
4
|
+
After=network-online.target
|
|
5
|
+
Wants=network-online.target
|
|
6
|
+
|
|
7
|
+
[Service]
|
|
8
|
+
Type=simple
|
|
9
|
+
User=w2m
|
|
10
|
+
Group=w2m
|
|
11
|
+
WorkingDirectory=/opt/w2m/app
|
|
12
|
+
ExecStart=/usr/local/bin/node /opt/w2m/app/bin/w2m-rabbit.mjs --host 0.0.0.0 --port 8787 --state /var/lib/w2m/rabbit
|
|
13
|
+
Restart=always
|
|
14
|
+
RestartSec=2
|
|
15
|
+
# The relay holds no model credentials and no working copy; it needs its state dir and
|
|
16
|
+
# nothing else. NoNewPrivileges + ProtectSystem close the obvious escalation paths.
|
|
17
|
+
NoNewPrivileges=true
|
|
18
|
+
PrivateTmp=true
|
|
19
|
+
ProtectSystem=full
|
|
20
|
+
ProtectHome=true
|
|
21
|
+
ReadWritePaths=/var/lib/w2m
|
|
22
|
+
StandardOutput=append:/var/log/w2m/rabbit.log
|
|
23
|
+
StandardError=append:/var/log/w2m/rabbit.log
|
|
24
|
+
|
|
25
|
+
[Install]
|
|
26
|
+
WantedBy=multi-user.target
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
[Unit]
|
|
2
|
+
Description=W2M STUN responder - reflexive address discovery for P2P hole punching
|
|
3
|
+
After=network-online.target
|
|
4
|
+
Wants=network-online.target
|
|
5
|
+
|
|
6
|
+
[Service]
|
|
7
|
+
Type=simple
|
|
8
|
+
User=w2m
|
|
9
|
+
Group=w2m
|
|
10
|
+
ExecStart=/usr/local/bin/node /opt/w2m/app/bin/w2m-stun.mjs --host 0.0.0.0 --port 3478 --log-level info
|
|
11
|
+
Restart=always
|
|
12
|
+
RestartSec=2
|
|
13
|
+
StartLimitIntervalSec=60
|
|
14
|
+
StartLimitBurst=5
|
|
15
|
+
NoNewPrivileges=true
|
|
16
|
+
PrivateTmp=true
|
|
17
|
+
ProtectSystem=strict
|
|
18
|
+
ProtectHome=true
|
|
19
|
+
ProtectKernelTunables=true
|
|
20
|
+
ProtectControlGroups=true
|
|
21
|
+
RestrictAddressFamilies=AF_INET AF_INET6
|
|
22
|
+
StandardOutput=append:/var/log/w2m/stun.log
|
|
23
|
+
StandardError=append:/var/log/w2m/stun.log
|
|
24
|
+
|
|
25
|
+
[Install]
|
|
26
|
+
WantedBy=multi-user.target
|