@skylandnpm/octopus-proxy 0.1.50 → 0.1.51
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/dist/{chunk-6NV726RL.js → chunk-55TEBVWY.js} +1 -1
- package/dist/{chunk-PPH4OB7Y.js → chunk-XIJKEY4L.js} +13 -9
- package/dist/cli.js +2 -2
- package/dist/main.js +2 -2
- package/dist/remote-worker.js +1 -1
- package/native/desktop-macos.m +3 -1
- package/native/remote-macos.m +31 -6
- package/package.json +1 -1
|
@@ -4187,7 +4187,7 @@ function assertLgplFFmpeg(output) {
|
|
|
4187
4187
|
import { execFile } from "node:child_process";
|
|
4188
4188
|
import { promisify } from "node:util";
|
|
4189
4189
|
import { createHash, randomUUID } from "node:crypto";
|
|
4190
|
-
import { chmod, mkdir, mkdtemp, readFile, rename, rm, stat } from "node:fs/promises";
|
|
4190
|
+
import { chmod, mkdir, mkdtemp, readFile, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
4191
4191
|
import { join } from "node:path";
|
|
4192
4192
|
import { fileURLToPath } from "node:url";
|
|
4193
4193
|
var DESKTOP_IMAGE_LIMIT = 20 * 1024 * 1024;
|
|
@@ -4257,16 +4257,20 @@ var PlatformDesktop = class {
|
|
|
4257
4257
|
await mkdir(this.stateDirectory, { recursive: true, mode: 448 });
|
|
4258
4258
|
const target = join(this.stateDirectory, "octopus-desktop-capture");
|
|
4259
4259
|
const source = fileURLToPath(new URL("../native/desktop-macos.m", import.meta.url));
|
|
4260
|
-
const
|
|
4261
|
-
|
|
4262
|
-
const
|
|
4260
|
+
const flags = ["-O2", "-fobjc-arc", "-mmacosx-version-min=12.3", "-framework", "Foundation", "-framework", "AppKit", "-framework", "ScreenCaptureKit", "-framework", "CoreMedia", "-framework", "CoreVideo", "-framework", "VideoToolbox", "-framework", "ImageIO"];
|
|
4261
|
+
const fingerprint = createHash("sha256").update(await readFile(source)).update(JSON.stringify([process.arch, flags])).digest("hex");
|
|
4262
|
+
const stamp = `${target}.sha256`, existing = await stat(target).catch(() => null);
|
|
4263
|
+
if (existing?.isFile() && (existing.mode & 63) === 0 && await readFile(stamp, "utf8").catch(() => "") === fingerprint) return target;
|
|
4264
|
+
const temporary = `${target}.${randomUUID()}`, temporaryStamp = `${temporary}.sha256`;
|
|
4263
4265
|
try {
|
|
4264
|
-
await this.execute("/usr/bin/clang", [
|
|
4266
|
+
await this.execute("/usr/bin/clang", [...flags, source, "-o", temporary]);
|
|
4265
4267
|
await chmod(temporary, 448);
|
|
4268
|
+
await writeFile(temporaryStamp, fingerprint, { mode: 384 });
|
|
4266
4269
|
await rename(temporary, target);
|
|
4270
|
+
await rename(temporaryStamp, stamp);
|
|
4267
4271
|
return target;
|
|
4268
4272
|
} finally {
|
|
4269
|
-
await rm(temporary, { force: true });
|
|
4273
|
+
await Promise.all([rm(temporary, { force: true }), rm(temporaryStamp, { force: true })]);
|
|
4270
4274
|
}
|
|
4271
4275
|
})();
|
|
4272
4276
|
this.helper.catch(() => {
|
|
@@ -4447,7 +4451,7 @@ var DesktopManager = class {
|
|
|
4447
4451
|
// src/remote-native.ts
|
|
4448
4452
|
import { execFile as execFile2, spawn } from "node:child_process";
|
|
4449
4453
|
import { promisify as promisify2 } from "node:util";
|
|
4450
|
-
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, rename as rename2, rm as rm2, stat as stat2, writeFile } from "node:fs/promises";
|
|
4454
|
+
import { chmod as chmod2, mkdir as mkdir2, readFile as readFile2, rename as rename2, rm as rm2, stat as stat2, writeFile as writeFile2 } from "node:fs/promises";
|
|
4451
4455
|
import { join as join2 } from "node:path";
|
|
4452
4456
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
4453
4457
|
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
@@ -4461,7 +4465,7 @@ async function ensureRemoteHelper(stateDirectory) {
|
|
|
4461
4465
|
const source = fileURLToPath2(new URL(mac ? "../native/remote-macos.m" : "../native/remote-x11.c", import.meta.url));
|
|
4462
4466
|
const target = join2(stateDirectory, "octopus-remote-desktop");
|
|
4463
4467
|
const stamp = `${target}.sha256`;
|
|
4464
|
-
const flags = mac ? ["-O2", "-fobjc-arc", "-mmacosx-version-min=12.3", "-framework", "Foundation", "-framework", "AppKit", "-framework", "ScreenCaptureKit", "-framework", "CoreMedia", "-framework", "CoreVideo", "-framework", "ApplicationServices", "-framework", "Carbon"] : ["-O2", "-lX11", "-lXtst"];
|
|
4468
|
+
const flags = mac ? ["-O2", "-fobjc-arc", "-mmacosx-version-min=12.3", "-framework", "Foundation", "-framework", "AppKit", "-framework", "ScreenCaptureKit", "-framework", "CoreMedia", "-framework", "CoreVideo", "-framework", "ApplicationServices", "-framework", "Carbon", "-framework", "IOKit"] : ["-O2", "-lX11", "-lXtst"];
|
|
4465
4469
|
const fingerprint = createHash2("sha256").update(await readFile2(source)).update(JSON.stringify([process.platform, process.arch, flags])).digest("hex");
|
|
4466
4470
|
const existing = await stat2(target).catch(() => void 0);
|
|
4467
4471
|
if (existing?.isFile() && (existing.mode & 63) === 0 && await readFile2(stamp, "utf8").catch(() => "") === fingerprint) return target;
|
|
@@ -4470,7 +4474,7 @@ async function ensureRemoteHelper(stateDirectory) {
|
|
|
4470
4474
|
try {
|
|
4471
4475
|
await exec(mac ? "/usr/bin/clang" : "cc", args, { timeout: 6e4, maxBuffer: 16384 });
|
|
4472
4476
|
await chmod2(temporary, 448);
|
|
4473
|
-
await
|
|
4477
|
+
await writeFile2(temporaryStamp, fingerprint, { mode: 384 });
|
|
4474
4478
|
await rename2(temporary, target);
|
|
4475
4479
|
await rename2(temporaryStamp, stamp);
|
|
4476
4480
|
return target;
|
package/dist/cli.js
CHANGED
|
@@ -31,13 +31,13 @@ import {
|
|
|
31
31
|
supportedPlatform,
|
|
32
32
|
systemdUnitPath,
|
|
33
33
|
toolSearchDirs
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-55TEBVWY.js";
|
|
35
35
|
import {
|
|
36
36
|
DESKTOP_PERMISSION_GUIDANCE,
|
|
37
37
|
PlatformDesktop,
|
|
38
38
|
checkDesktop,
|
|
39
39
|
requestDesktopPermission
|
|
40
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-XIJKEY4L.js";
|
|
41
41
|
|
|
42
42
|
// src/cli.ts
|
|
43
43
|
import { spawn as spawn2 } from "node:child_process";
|
package/dist/main.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import {
|
|
3
3
|
ConfigError,
|
|
4
4
|
runDaemon
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-55TEBVWY.js";
|
|
6
|
+
import "./chunk-XIJKEY4L.js";
|
|
7
7
|
|
|
8
8
|
// src/main.ts
|
|
9
9
|
runDaemon(process.env.OCTOPUS_PROXY_CONFIG ?? "proxy.json").catch((error) => {
|
package/dist/remote-worker.js
CHANGED
package/native/desktop-macos.m
CHANGED
|
@@ -106,7 +106,9 @@ int main(int argc, const char *argv[]) {
|
|
|
106
106
|
if (argc == 2 && strcmp(argv[1], "list") == 0) {
|
|
107
107
|
CGDirectDisplayID ids[64];
|
|
108
108
|
uint32_t count = 0;
|
|
109
|
-
|
|
109
|
+
// Sleeping displays are still connected and must remain selectable so
|
|
110
|
+
// an authenticated remote connection can wake them with user input.
|
|
111
|
+
if (CGGetOnlineDisplayList(64, ids, &count) != kCGErrorSuccess) {
|
|
110
112
|
fail(@"无法读取活动显示器,请检查 Proxy 是否运行在已登录的图形桌面会话中。" );
|
|
111
113
|
return 1;
|
|
112
114
|
}
|
package/native/remote-macos.m
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
#import <ApplicationServices/ApplicationServices.h>
|
|
4
4
|
#import <ScreenCaptureKit/ScreenCaptureKit.h>
|
|
5
5
|
#import <Carbon/Carbon.h>
|
|
6
|
+
#import <IOKit/pwr_mgt/IOPMLib.h>
|
|
6
7
|
#include <arpa/inet.h>
|
|
7
8
|
#include <fcntl.h>
|
|
8
9
|
#include <signal.h>
|
|
@@ -17,6 +18,8 @@ static NSMutableSet<NSNumber *> *heldKeys;
|
|
|
17
18
|
static BOOL heldButtons[3];
|
|
18
19
|
static double lastPing;
|
|
19
20
|
static pid_t parentPID;
|
|
21
|
+
static IOPMAssertionID activityAssertion = kIOPMNullAssertionID;
|
|
22
|
+
static double lastActivity;
|
|
20
23
|
static void signalStop(int signal) { stopping = 1; }
|
|
21
24
|
static BOOL sessionPresent(void) {
|
|
22
25
|
NSDictionary *s = CFBridgingRelease(CGSessionCopyCurrentDictionary());
|
|
@@ -29,6 +32,19 @@ static BOOL screenLocked(void) {
|
|
|
29
32
|
return [s[@"CGSSessionScreenIsLocked"] boolValue];
|
|
30
33
|
}
|
|
31
34
|
static BOOL inputOK(void) { return AXIsProcessTrusted() && CGPreflightPostEventAccess() && sessionPresent(); }
|
|
35
|
+
// Quartz events can fill the password field without marking the console user
|
|
36
|
+
// active. loginwindow then times out its activity check and reports a bad
|
|
37
|
+
// password. Declare activity on connection and real console input, never on
|
|
38
|
+
// capture/pings. This also wakes a sleeping connected display.
|
|
39
|
+
static void userActivity(void) {
|
|
40
|
+
double now=NSProcessInfo.processInfo.systemUptime;
|
|
41
|
+
if(activityAssertion!=kIOPMNullAssertionID && now-lastActivity<1) return;
|
|
42
|
+
if(IOPMAssertionDeclareUserActivity(CFSTR("Octopus remote console input"),kIOPMUserActiveLocal,&activityAssertion)==kIOReturnSuccess) lastActivity=now;
|
|
43
|
+
}
|
|
44
|
+
static void releaseActivity(void) {
|
|
45
|
+
if(activityAssertion!=kIOPMNullAssertionID) IOPMAssertionRelease(activityAssertion);
|
|
46
|
+
activityAssertion=kIOPMNullAssertionID; lastActivity=0;
|
|
47
|
+
}
|
|
32
48
|
static void emit(NSDictionary *value) {
|
|
33
49
|
NSData *data = [NSJSONSerialization dataWithJSONObject:value options:0 error:NULL];
|
|
34
50
|
if (!data) return;
|
|
@@ -205,15 +221,18 @@ static void command(NSString *line,RemoteStream *capture) {
|
|
|
205
221
|
}
|
|
206
222
|
if (([op isEqual:@"pointer"] && parts.count==3) || ([op isEqual:@"button"] && parts.count==5) || ([op isEqual:@"wheel"] && parts.count==5)) {
|
|
207
223
|
position(parts[1].doubleValue,parts[2].doubleValue);
|
|
208
|
-
if ([op isEqual:@"button"]
|
|
224
|
+
if ([op isEqual:@"button"] && (parts[3].intValue<0 || parts[3].intValue>2)) { stopping=1; return; }
|
|
225
|
+
userActivity();
|
|
226
|
+
if ([op isEqual:@"button"]) { int button=parts[3].intValue; heldButtons[button]=parts[4].boolValue; mouseEvent(mouseType(button,heldButtons[button]),mouseButton(button)); }
|
|
209
227
|
else if ([op isEqual:@"wheel"]) { mouseEvent(kCGEventMouseMoved,kCGMouseButtonLeft); CGEventRef e=CGEventCreateScrollWheelEvent(NULL,kCGScrollEventUnitPixel,2,-parts[4].intValue,-parts[3].intValue); if(e) { CGEventSetFlags(e,flags()); CGEventPost(kCGHIDEventTap,e); CFRelease(e); } }
|
|
210
228
|
else { CGEventType type=heldButtons[0]?kCGEventLeftMouseDragged:heldButtons[2]?kCGEventRightMouseDragged:heldButtons[1]?kCGEventOtherMouseDragged:kCGEventMouseMoved; mouseEvent(type,heldButtons[2]?kCGMouseButtonRight:heldButtons[1]?kCGMouseButtonCenter:kCGMouseButtonLeft); }
|
|
211
|
-
} else if ([op isEqual:@"key"] && parts.count==3) { NSNumber *key=keyCodes()[parts[1]]; if(key) keyEvent(key.unsignedShortValue,parts[2].boolValue); }
|
|
229
|
+
} else if ([op isEqual:@"key"] && parts.count==3) { NSNumber *key=keyCodes()[parts[1]]; if(key) { userActivity(); keyEvent(key.unsignedShortValue,parts[2].boolValue); } }
|
|
212
230
|
else if (([op isEqual:@"text"] && parts.count==3) || ([op isEqual:@"password"] && parts.count==2)) {
|
|
213
231
|
BOOL password=[op isEqual:@"password"];
|
|
214
232
|
NSData *data=[[NSData alloc] initWithBase64EncodedString:parts[password ? 1 : 2] options:0]; NSString *text=[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
|
215
233
|
if(!text || data.length>(password ? 1024 : 16384) || (password && (!data.length || [text rangeOfCharacterFromSet:NSCharacterSet.controlCharacterSet].location!=NSNotFound))) { stopping=1; return; }
|
|
216
234
|
if(password && !screenLocked()) { emit(@{@"kind":@"input-error"}); return; }
|
|
235
|
+
if(text.length) userActivity();
|
|
217
236
|
releaseAll();
|
|
218
237
|
for(NSUInteger i=0;i<text.length;) {
|
|
219
238
|
if(!inputOK()) { stopping=1; return; }
|
|
@@ -252,9 +271,15 @@ int main(int argc,const char *argv[]) {
|
|
|
252
271
|
emit(@{@"capture":@(CGPreflightScreenCaptureAccess()),@"input":@((BOOL)(AXIsProcessTrusted() && CGPreflightPostEventAccess())),@"session":@(sessionPresent()),@"locked":@(screenLocked()),@"lockCapture":@(lockCapture)}); return 0;
|
|
253
272
|
}
|
|
254
273
|
if(argc!=6 || strcmp(argv[1],"serve")!=0 || !inputOK() || !CGPreflightScreenCaptureAccess()) return 1;
|
|
255
|
-
displayID=(CGDirectDisplayID)strtoul(argv[2],NULL,10);
|
|
274
|
+
displayID=(CGDirectDisplayID)strtoul(argv[2],NULL,10);
|
|
256
275
|
int w=atoi(argv[3]),h=atoi(argv[4]),fps=atoi(argv[5]);
|
|
257
|
-
if(!
|
|
276
|
+
if(!CGDisplayIsOnline(displayID) || w<2 || h<2 || w>3840 || h>2160 || w%2 || h%2 || fps<1 || fps>30) return 1;
|
|
277
|
+
userActivity();
|
|
278
|
+
NSDate *wakeDeadline=[NSDate dateWithTimeIntervalSinceNow:2];
|
|
279
|
+
while(!CGDisplayIsActive(displayID) && CGDisplayIsOnline(displayID) && inputOK() && wakeDeadline.timeIntervalSinceNow>0)
|
|
280
|
+
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.02]];
|
|
281
|
+
if(!CGDisplayIsActive(displayID) || !inputOK()) { releaseActivity(); return 1; }
|
|
282
|
+
bounds=CGDisplayBounds(displayID);
|
|
258
283
|
heldKeys=[NSMutableSet set]; cursor=bounds.origin; parentPID=getppid(); lastPing=NSDate.date.timeIntervalSince1970;
|
|
259
284
|
signal(SIGTERM,signalStop); signal(SIGINT,signalStop); signal(SIGPIPE,signalStop);
|
|
260
285
|
fcntl(STDIN_FILENO,F_SETFL,O_NONBLOCK);
|
|
@@ -279,7 +304,7 @@ int main(int argc,const char *argv[]) {
|
|
|
279
304
|
NSMutableData *incoming=[NSMutableData data];
|
|
280
305
|
while(!stopping) {
|
|
281
306
|
@autoreleasepool {
|
|
282
|
-
if(getppid()!=parentPID || NSDate.date.timeIntervalSince1970-lastPing>15 || !inputOK() || !CGPreflightScreenCaptureAccess() || !
|
|
307
|
+
if(getppid()!=parentPID || NSDate.date.timeIntervalSince1970-lastPing>15 || !inputOK() || !CGPreflightScreenCaptureAccess() || !CGDisplayIsOnline(displayID) || !CGRectEqualToRect(bounds,CGDisplayBounds(displayID))) break;
|
|
283
308
|
if(screenLocked()) [capture captureLockedFrame];
|
|
284
309
|
else if(capture.streamStopped && capture.stream) {
|
|
285
310
|
capture.streamStopped=NO;
|
|
@@ -297,7 +322,7 @@ int main(int argc,const char *argv[]) {
|
|
|
297
322
|
[NSRunLoop.currentRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:.005]];
|
|
298
323
|
}
|
|
299
324
|
}
|
|
300
|
-
stopping=1; releaseAll(); [capture.stream stopCaptureWithCompletionHandler:nil]; return 0;
|
|
325
|
+
stopping=1; releaseAll(); releaseActivity(); [capture.stream stopCaptureWithCompletionHandler:nil]; return 0;
|
|
301
326
|
}
|
|
302
327
|
return 1;
|
|
303
328
|
}
|