pairling 0.2.7 → 0.2.9
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/README.md +10 -11
- package/bin/pairling.mjs +1 -4
- package/package.json +3 -3
- package/payload/mac/SOURCE_REVISION +1 -1
- package/payload/mac/VERSION +1 -1
- package/payload/mac/companiond/pairlingd.py +82 -145
- package/payload/mac/connectd/cmd/pairling-connectd/main.go +33 -9
- package/payload/mac/connectd/cmd/pairling-connectd/peer_identity_test.go +145 -5
- package/payload/mac/connectd/internal/gateway/proxy.go +16 -2
- package/payload/mac/connectd/internal/gateway/proxy_test.go +103 -4
- package/payload/mac/install/install-runtime.sh +113 -294
- package/payload/mac/install/render-launchd.py +2 -45
- package/payload/mac/install/uninstall-runtime.sh +32 -0
- package/payload-manifest.json +14 -36
- package/payload/mac/connectd/cmd/pairling-tailnet-mintd/main.go +0 -121
- package/payload/mac/connectd/cmd/pairling-tailnet-mintd/mintd.go +0 -418
- package/payload/mac/connectd/cmd/pairling-tailnet-mintd/mintd_test.go +0 -894
|
@@ -11,6 +11,11 @@ USER_PLIST="$HOME/Library/LaunchAgents/$PAIRLING_DAEMON_LABEL.plist"
|
|
|
11
11
|
CONNECTD_USER_PLIST="$HOME/Library/LaunchAgents/$PAIRLING_CONNECTD_LABEL.plist"
|
|
12
12
|
PTYBROKER_USER_PLIST="$HOME/Library/LaunchAgents/$PAIRLING_PTYBROKER_LABEL.plist"
|
|
13
13
|
SYSTEM_PLIST="/Library/LaunchDaemons/$PAIRLING_GUARDIAN_LABEL.plist"
|
|
14
|
+
# Legacy: the silent-join mint broker, removed from the product. Torn down below.
|
|
15
|
+
MINTD_SYSTEM_LABEL="dev.pairling.mintd"
|
|
16
|
+
MINTD_SYSTEM_PLIST="/Library/LaunchDaemons/$MINTD_SYSTEM_LABEL.plist"
|
|
17
|
+
MINTD_SYSTEM_DIR="/Library/Application Support/Pairling/mint"
|
|
18
|
+
MINTD_SERVICE_ACCOUNT="_pairling_mint"
|
|
14
19
|
YES="false"
|
|
15
20
|
DELETE_STATE="false"
|
|
16
21
|
DELETE_LOGS="false"
|
|
@@ -98,6 +103,32 @@ bootout_system() {
|
|
|
98
103
|
fi
|
|
99
104
|
}
|
|
100
105
|
|
|
106
|
+
# Legacy teardown: the silent-join mint broker (dev.pairling.mintd) was removed
|
|
107
|
+
# from the product. Machines that ran the old `enable-silent-join` still carry a
|
|
108
|
+
# root LaunchDaemon, a stored Tailscale OAuth secret under the system mint dir,
|
|
109
|
+
# and the _pairling_mint role account. Remove all three. Best-effort, sudo-gated.
|
|
110
|
+
teardown_legacy_mintd() {
|
|
111
|
+
if [[ ! -f "$MINTD_SYSTEM_PLIST" && ! -d "$MINTD_SYSTEM_DIR" ]] \
|
|
112
|
+
&& ! id -u "$MINTD_SERVICE_ACCOUNT" >/dev/null 2>&1; then
|
|
113
|
+
return
|
|
114
|
+
fi
|
|
115
|
+
if is_dry_run; then
|
|
116
|
+
printf 'dry-run: would remove the legacy silent-join mint broker (%s, %s, user %s)\n' \
|
|
117
|
+
"$MINTD_SYSTEM_PLIST" "$MINTD_SYSTEM_DIR" "$MINTD_SERVICE_ACCOUNT"
|
|
118
|
+
return
|
|
119
|
+
fi
|
|
120
|
+
if sudo -n true >/dev/null 2>&1; then
|
|
121
|
+
sudo launchctl bootout "system/$MINTD_SYSTEM_LABEL" >/dev/null 2>&1 || true
|
|
122
|
+
sudo launchctl bootout system "$MINTD_SYSTEM_PLIST" >/dev/null 2>&1 || true
|
|
123
|
+
sudo rm -f "$MINTD_SYSTEM_PLIST"
|
|
124
|
+
sudo rm -rf "$MINTD_SYSTEM_DIR"
|
|
125
|
+
sudo /usr/sbin/sysadminctl -deleteUser "$MINTD_SERVICE_ACCOUNT" >/dev/null 2>&1 || true
|
|
126
|
+
printf 'Removed the legacy silent-join mint broker.\n'
|
|
127
|
+
else
|
|
128
|
+
printf 'Skipping legacy mint-broker removal: passwordless sudo is unavailable.\n' >&2
|
|
129
|
+
fi
|
|
130
|
+
}
|
|
131
|
+
|
|
101
132
|
confirm
|
|
102
133
|
|
|
103
134
|
bootout_user "$PAIRLING_DAEMON_LABEL" "$USER_PLIST"
|
|
@@ -107,6 +138,7 @@ rm -f "$USER_PLIST"
|
|
|
107
138
|
rm -f "$CONNECTD_USER_PLIST"
|
|
108
139
|
rm -f "$PTYBROKER_USER_PLIST"
|
|
109
140
|
bootout_system "$PAIRLING_GUARDIAN_LABEL" "$SYSTEM_PLIST"
|
|
141
|
+
teardown_legacy_mintd
|
|
110
142
|
|
|
111
143
|
rm -rf "$APP_SUPPORT/pair" 2>/dev/null || true
|
|
112
144
|
|
package/payload-manifest.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"connectd": {
|
|
3
3
|
"darwin-arm64": {
|
|
4
|
-
"sha256": "
|
|
4
|
+
"sha256": "3ee070f12619390609a8c76e0ae4803ab1bc48c9f77361b8f27a4125846f38e3",
|
|
5
5
|
"team_id": "965AVD34A3"
|
|
6
6
|
},
|
|
7
7
|
"darwin-x64": {
|
|
8
|
-
"sha256": "
|
|
8
|
+
"sha256": "c1ee211c3da71200d7855c9246ea04cd25fda702f7fb33a366b4d51bdaf9e230",
|
|
9
9
|
"team_id": "965AVD34A3"
|
|
10
10
|
}
|
|
11
11
|
},
|
|
@@ -20,11 +20,11 @@
|
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
"path": "payload/mac/SOURCE_REVISION",
|
|
23
|
-
"sha256": "
|
|
23
|
+
"sha256": "29c2c816c529155cc86f26d44a8e8d79fc170fc26ade74fac3780554b5c864ff"
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
"path": "payload/mac/VERSION",
|
|
27
|
-
"sha256": "
|
|
27
|
+
"sha256": "2f2b333be8858cb384114251b668bb1c9e45a0bb8393600b7ad4093d0e8e72f6"
|
|
28
28
|
},
|
|
29
29
|
{
|
|
30
30
|
"path": "payload/mac/companiond/app_attest_lan.py",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
},
|
|
97
97
|
{
|
|
98
98
|
"path": "payload/mac/companiond/pairlingd.py",
|
|
99
|
-
"sha256": "
|
|
99
|
+
"sha256": "ca1c5551dd235990d4ff8d8b9c3c3f25e912ca9c22c7003f50c9fe1ccb6bf02e"
|
|
100
100
|
},
|
|
101
101
|
{
|
|
102
102
|
"path": "payload/mac/companiond/providers/__init__.py",
|
|
@@ -200,28 +200,16 @@
|
|
|
200
200
|
},
|
|
201
201
|
{
|
|
202
202
|
"path": "payload/mac/connectd/cmd/pairling-connectd/main.go",
|
|
203
|
-
"sha256": "
|
|
203
|
+
"sha256": "019288bd16c6e900c60206ee4739f9ae5ed640ea73cd57db6a1f0d618c9bf00c"
|
|
204
204
|
},
|
|
205
205
|
{
|
|
206
206
|
"path": "payload/mac/connectd/cmd/pairling-connectd/peer_identity_test.go",
|
|
207
|
-
"sha256": "
|
|
207
|
+
"sha256": "eb1f44e588c2d70e2660f805ee6b7fe09aa793365c0ae442164785a8241c35d8"
|
|
208
208
|
},
|
|
209
209
|
{
|
|
210
210
|
"path": "payload/mac/connectd/cmd/pairling-connectd/upstream_health_test.go",
|
|
211
211
|
"sha256": "dc5b6d3a8d11f38bcc198287bdbc95f058d35792ca6cf34bc49ca0bed22bfacf"
|
|
212
212
|
},
|
|
213
|
-
{
|
|
214
|
-
"path": "payload/mac/connectd/cmd/pairling-tailnet-mintd/main.go",
|
|
215
|
-
"sha256": "64fd4527c97397fce10793001af8d59ac3154c75c7ed9e1b532f8f2e4bf88bd4"
|
|
216
|
-
},
|
|
217
|
-
{
|
|
218
|
-
"path": "payload/mac/connectd/cmd/pairling-tailnet-mintd/mintd.go",
|
|
219
|
-
"sha256": "ca49b8ab8216eeec770ad6e9e8111aca819a9a88b050d7eefbdf69c0fad20376"
|
|
220
|
-
},
|
|
221
|
-
{
|
|
222
|
-
"path": "payload/mac/connectd/cmd/pairling-tailnet-mintd/mintd_test.go",
|
|
223
|
-
"sha256": "14a9af6b9575ba89314ce05f2fe465844fea3bb40b3eba5e0d33d059608bfb1f"
|
|
224
|
-
},
|
|
225
213
|
{
|
|
226
214
|
"path": "payload/mac/connectd/go.mod",
|
|
227
215
|
"sha256": "c96748d396598b0952b4c0d43f7f85ca3a56f4019761088267421b22518d5905"
|
|
@@ -244,11 +232,11 @@
|
|
|
244
232
|
},
|
|
245
233
|
{
|
|
246
234
|
"path": "payload/mac/connectd/internal/gateway/proxy.go",
|
|
247
|
-
"sha256": "
|
|
235
|
+
"sha256": "b852408a35b71a0b62554cc93f413c3352034432f14529ab3ddbe85fa5ee49c8"
|
|
248
236
|
},
|
|
249
237
|
{
|
|
250
238
|
"path": "payload/mac/connectd/internal/gateway/proxy_test.go",
|
|
251
|
-
"sha256": "
|
|
239
|
+
"sha256": "f3a6b1974c1ccba8e5e380d18c31a5aca61458b6d4a1075865b8978e86e54209"
|
|
252
240
|
},
|
|
253
241
|
{
|
|
254
242
|
"path": "payload/mac/connectd/internal/runtime/config.go",
|
|
@@ -284,7 +272,7 @@
|
|
|
284
272
|
},
|
|
285
273
|
{
|
|
286
274
|
"path": "payload/mac/install/install-runtime.sh",
|
|
287
|
-
"sha256": "
|
|
275
|
+
"sha256": "40ffa67a3833ce4342c241ca4f1e7dec471a86b0c80359746cd75a8df2e33f60"
|
|
288
276
|
},
|
|
289
277
|
{
|
|
290
278
|
"path": "payload/mac/install/psk_dependency_check.py",
|
|
@@ -292,11 +280,11 @@
|
|
|
292
280
|
},
|
|
293
281
|
{
|
|
294
282
|
"path": "payload/mac/install/render-launchd.py",
|
|
295
|
-
"sha256": "
|
|
283
|
+
"sha256": "29db1aa46d62cd23ba27ab283bb990d168bfc08fb82cfc681046dc7b887d85fe"
|
|
296
284
|
},
|
|
297
285
|
{
|
|
298
286
|
"path": "payload/mac/install/uninstall-runtime.sh",
|
|
299
|
-
"sha256": "
|
|
287
|
+
"sha256": "0edeb5336a71c235d8796a8e59072c6d8983d196de5aae0cfcb4b0c3560fa33f"
|
|
300
288
|
},
|
|
301
289
|
{
|
|
302
290
|
"path": "payload/mac/mcp/phone_tools.py",
|
|
@@ -307,19 +295,9 @@
|
|
|
307
295
|
"sha256": "5ebcd63fc53114ace518807c2221e562e65237e57945a76c457f5931a5791cc1"
|
|
308
296
|
}
|
|
309
297
|
],
|
|
310
|
-
"mintd": {
|
|
311
|
-
"darwin-arm64": {
|
|
312
|
-
"sha256": "326d1d42a0b40bdb60687f7b7d190c12c520106e47542054b1b807d397e41fe9",
|
|
313
|
-
"team_id": "965AVD34A3"
|
|
314
|
-
},
|
|
315
|
-
"darwin-x64": {
|
|
316
|
-
"sha256": "477cf4d9b88f1e8303e5545eb3c03460e0c75b284f9d628641cb80e2be14af38",
|
|
317
|
-
"team_id": "965AVD34A3"
|
|
318
|
-
}
|
|
319
|
-
},
|
|
320
298
|
"package": "pairling",
|
|
321
|
-
"package_version": "0.2.
|
|
299
|
+
"package_version": "0.2.9",
|
|
322
300
|
"schema_version": 1,
|
|
323
301
|
"source_dirty": false,
|
|
324
|
-
"source_revision": "
|
|
302
|
+
"source_revision": "c97bbab"
|
|
325
303
|
}
|
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
package main
|
|
2
|
-
|
|
3
|
-
import (
|
|
4
|
-
"context"
|
|
5
|
-
"encoding/json"
|
|
6
|
-
"errors"
|
|
7
|
-
"flag"
|
|
8
|
-
"fmt"
|
|
9
|
-
"log"
|
|
10
|
-
"net/http"
|
|
11
|
-
"os"
|
|
12
|
-
"os/exec"
|
|
13
|
-
"os/signal"
|
|
14
|
-
"strconv"
|
|
15
|
-
"strings"
|
|
16
|
-
"syscall"
|
|
17
|
-
"time"
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
func main() {
|
|
21
|
-
var (
|
|
22
|
-
secretPath = flag.String("secret-path", "/Library/Application Support/Pairling/mint/client_secret.json", "OAuth client credential JSON")
|
|
23
|
-
socketPath = flag.String("socket-path", "/Library/Application Support/Pairling/run/mintd/mintd.sock", "Unix socket path")
|
|
24
|
-
statePath = flag.String("state-path", "/Library/Application Support/Pairling/mint/state.json", "persistent rate-limit state JSON")
|
|
25
|
-
auditPath = flag.String("audit-path", "/Library/Application Support/Pairling/mint/audit.jsonl", "audit JSONL path")
|
|
26
|
-
alertPath = flag.String("alert-path", "/Library/Application Support/Pairling/run/mintd/alerts.jsonl", "health-readable alert JSONL path")
|
|
27
|
-
apiBaseURL = flag.String("api-base-url", "https://api.tailscale.com/api/v2", "Tailscale API base URL")
|
|
28
|
-
oauthURL = flag.String("oauth-url", "https://api.tailscale.com/api/v2/oauth/token", "Tailscale OAuth token URL")
|
|
29
|
-
authorizedUID = flag.Int("authorized-uid", -1, "only this peer uid may request mints")
|
|
30
|
-
)
|
|
31
|
-
flag.Parse()
|
|
32
|
-
|
|
33
|
-
b, err := NewBroker(BrokerConfig{
|
|
34
|
-
SecretPath: *secretPath,
|
|
35
|
-
StatePath: *statePath,
|
|
36
|
-
AuditPath: *auditPath,
|
|
37
|
-
AlertPath: *alertPath,
|
|
38
|
-
OAuthURL: *oauthURL,
|
|
39
|
-
APIBaseURL: *apiBaseURL,
|
|
40
|
-
LockStatus: defaultLockStatus,
|
|
41
|
-
})
|
|
42
|
-
if err != nil {
|
|
43
|
-
log.Fatal(err)
|
|
44
|
-
}
|
|
45
|
-
ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)
|
|
46
|
-
defer stop()
|
|
47
|
-
if err := b.ServeUnix(ctx, *socketPath, *authorizedUID); err != nil {
|
|
48
|
-
log.Fatal(err)
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
func defaultLockStatus(ctx context.Context) (bool, error) {
|
|
53
|
-
if locked, err := lockStatusFromConnectdStatus(ctx, "http://127.0.0.1:7774/status"); err == nil {
|
|
54
|
-
return locked, nil
|
|
55
|
-
}
|
|
56
|
-
return lockStatusFromCandidates(ctx, []string{
|
|
57
|
-
"/opt/homebrew/bin/tailscale",
|
|
58
|
-
"/Applications/Tailscale.app/Contents/MacOS/Tailscale",
|
|
59
|
-
"tailscale",
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
func lockStatusFromConnectdStatus(ctx context.Context, statusURL string) (bool, error) {
|
|
64
|
-
req, err := http.NewRequestWithContext(ctx, http.MethodGet, statusURL, nil)
|
|
65
|
-
if err != nil {
|
|
66
|
-
return false, err
|
|
67
|
-
}
|
|
68
|
-
resp, err := (&http.Client{Timeout: 2 * time.Second}).Do(req)
|
|
69
|
-
if err != nil {
|
|
70
|
-
return false, err
|
|
71
|
-
}
|
|
72
|
-
defer resp.Body.Close()
|
|
73
|
-
if resp.StatusCode != http.StatusOK {
|
|
74
|
-
return false, fmt.Errorf("connectd status returned %s", resp.Status)
|
|
75
|
-
}
|
|
76
|
-
var body struct {
|
|
77
|
-
TailnetLockEnabled *bool `json:"tailnet_lock_enabled"`
|
|
78
|
-
}
|
|
79
|
-
if err := json.NewDecoder(resp.Body).Decode(&body); err != nil {
|
|
80
|
-
return false, err
|
|
81
|
-
}
|
|
82
|
-
if body.TailnetLockEnabled == nil {
|
|
83
|
-
return false, errors.New("connectd status omitted tailnet_lock_enabled")
|
|
84
|
-
}
|
|
85
|
-
return *body.TailnetLockEnabled, nil
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
func lockStatusFromCandidates(ctx context.Context, candidates []string) (bool, error) {
|
|
89
|
-
var errs []error
|
|
90
|
-
for _, bin := range candidates {
|
|
91
|
-
out, err := exec.CommandContext(ctx, bin, "lock", "status").CombinedOutput()
|
|
92
|
-
if err != nil {
|
|
93
|
-
errs = append(errs, fmt.Errorf("%s: %w", bin, err))
|
|
94
|
-
continue
|
|
95
|
-
}
|
|
96
|
-
text := strings.ToLower(string(out))
|
|
97
|
-
if strings.Contains(text, "tailscale gui failed to start") {
|
|
98
|
-
errs = append(errs, fmt.Errorf("%s: gui unavailable", bin))
|
|
99
|
-
continue
|
|
100
|
-
}
|
|
101
|
-
if strings.Contains(text, "not enabled") || strings.Contains(text, "disabled") {
|
|
102
|
-
return false, nil
|
|
103
|
-
}
|
|
104
|
-
if strings.Contains(text, "enabled") {
|
|
105
|
-
return true, nil
|
|
106
|
-
}
|
|
107
|
-
return false, fmt.Errorf("unrecognized tailscale lock status: %q", strings.TrimSpace(string(out)))
|
|
108
|
-
}
|
|
109
|
-
return false, errors.New("tailscale lock status unavailable: " + joinErrors(errs))
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
func joinErrors(errs []error) string {
|
|
113
|
-
parts := make([]string, 0, len(errs))
|
|
114
|
-
for _, err := range errs {
|
|
115
|
-
parts = append(parts, err.Error())
|
|
116
|
-
}
|
|
117
|
-
if len(parts) == 0 {
|
|
118
|
-
return "no candidates"
|
|
119
|
-
}
|
|
120
|
-
return strconv.Quote(strings.Join(parts, "; "))
|
|
121
|
-
}
|