@yume-chan/adb 0.0.18 → 0.0.20
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.json +54 -0
- package/CHANGELOG.md +25 -1
- package/README.md +220 -103
- package/esm/adb.d.ts +43 -60
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +68 -249
- package/esm/adb.js.map +1 -1
- package/esm/banner.d.ts +17 -0
- package/esm/banner.d.ts.map +1 -0
- package/esm/banner.js +67 -0
- package/esm/banner.js.map +1 -0
- package/esm/commands/base.d.ts +6 -6
- package/esm/commands/base.d.ts.map +1 -1
- package/esm/commands/base.js +8 -8
- package/esm/commands/framebuffer.d.ts +53 -53
- package/esm/commands/framebuffer.d.ts.map +1 -1
- package/esm/commands/framebuffer.js +46 -46
- package/esm/commands/framebuffer.js.map +1 -1
- package/esm/commands/index.d.ts +7 -8
- package/esm/commands/index.d.ts.map +1 -1
- package/esm/commands/index.js +7 -8
- package/esm/commands/index.js.map +1 -1
- package/esm/commands/power.d.ts +22 -22
- package/esm/commands/power.js +48 -48
- package/esm/commands/reverse.d.ts +40 -28
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +130 -100
- package/esm/commands/reverse.js.map +1 -1
- package/esm/commands/subprocess/command.d.ts +57 -51
- package/esm/commands/subprocess/command.d.ts.map +1 -1
- package/esm/commands/subprocess/command.js +86 -80
- package/esm/commands/subprocess/command.js.map +1 -1
- package/esm/commands/subprocess/index.d.ts +3 -3
- package/esm/commands/subprocess/index.js +3 -3
- package/esm/commands/subprocess/protocols/index.d.ts +3 -3
- package/esm/commands/subprocess/protocols/index.js +3 -3
- package/esm/commands/subprocess/protocols/none.d.ts +30 -35
- package/esm/commands/subprocess/protocols/none.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/none.js +65 -55
- package/esm/commands/subprocess/protocols/none.js.map +1 -1
- package/esm/commands/subprocess/protocols/shell.d.ts +33 -38
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +172 -162
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +48 -49
- package/esm/commands/subprocess/protocols/types.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/types.js +1 -1
- package/esm/commands/subprocess/utils.d.ts +1 -1
- package/esm/commands/subprocess/utils.js +18 -18
- package/esm/commands/sync/index.d.ts +8 -7
- package/esm/commands/sync/index.d.ts.map +1 -1
- package/esm/commands/sync/index.js +8 -7
- package/esm/commands/sync/index.js.map +1 -1
- package/esm/commands/sync/list.d.ts +42 -40
- package/esm/commands/sync/list.d.ts.map +1 -1
- package/esm/commands/sync/list.js +67 -47
- package/esm/commands/sync/list.js.map +1 -1
- package/esm/commands/sync/pull.d.ts +13 -11
- package/esm/commands/sync/pull.d.ts.map +1 -1
- package/esm/commands/sync/pull.js +35 -37
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +57 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +89 -22
- package/esm/commands/sync/push.js.map +1 -1
- package/esm/commands/sync/request.d.ts +26 -23
- package/esm/commands/sync/request.d.ts.map +1 -1
- package/esm/commands/sync/request.js +40 -42
- package/esm/commands/sync/request.js.map +1 -1
- package/esm/commands/sync/response.d.ts +19 -19
- package/esm/commands/sync/response.d.ts.map +1 -1
- package/esm/commands/sync/response.js +54 -54
- package/esm/commands/sync/response.js.map +1 -1
- package/esm/commands/sync/socket.d.ts +22 -0
- package/esm/commands/sync/socket.d.ts.map +1 -0
- package/esm/commands/sync/socket.js +69 -0
- package/esm/commands/sync/socket.js.map +1 -0
- package/esm/commands/sync/stat.d.ts +72 -72
- package/esm/commands/sync/stat.d.ts.map +1 -1
- package/esm/commands/sync/stat.js +116 -104
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +65 -60
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +123 -149
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +5 -5
- package/esm/commands/tcpip.d.ts.map +1 -1
- package/esm/commands/tcpip.js +20 -18
- package/esm/commands/tcpip.js.map +1 -1
- package/esm/{auth.d.ts → daemon/auth.d.ts} +50 -51
- package/esm/daemon/auth.d.ts.map +1 -0
- package/esm/{auth.js → daemon/auth.js} +95 -96
- package/esm/daemon/auth.js.map +1 -0
- package/esm/daemon/connection.d.ts +11 -0
- package/esm/daemon/connection.d.ts.map +1 -0
- package/esm/daemon/connection.js +2 -0
- package/esm/daemon/connection.js.map +1 -0
- package/esm/{crypto.d.ts → daemon/crypto.d.ts} +36 -36
- package/esm/daemon/crypto.d.ts.map +1 -0
- package/esm/{crypto.js → daemon/crypto.js} +244 -248
- package/esm/daemon/crypto.js.map +1 -0
- package/esm/daemon/device.d.ts +9 -0
- package/esm/daemon/device.d.ts.map +1 -0
- package/esm/daemon/device.js +2 -0
- package/esm/daemon/device.js.map +1 -0
- package/esm/daemon/dispatcher.d.ts +42 -0
- package/esm/daemon/dispatcher.d.ts.map +1 -0
- package/esm/{socket → daemon}/dispatcher.js +225 -234
- package/esm/daemon/dispatcher.js.map +1 -0
- package/esm/daemon/index.d.ts +8 -0
- package/esm/daemon/index.d.ts.map +1 -0
- package/esm/daemon/index.js +8 -0
- package/esm/daemon/index.js.map +1 -0
- package/esm/{packet.d.ts → daemon/packet.d.ts} +45 -46
- package/esm/daemon/packet.d.ts.map +1 -0
- package/esm/{packet.js → daemon/packet.js} +43 -48
- package/esm/daemon/packet.js.map +1 -0
- package/esm/daemon/socket.d.ts +58 -0
- package/esm/daemon/socket.d.ts.map +1 -0
- package/esm/{socket → daemon}/socket.js +121 -118
- package/esm/daemon/socket.js.map +1 -0
- package/esm/daemon/transport.d.ts +45 -0
- package/esm/daemon/transport.d.ts.map +1 -0
- package/esm/daemon/transport.js +184 -0
- package/esm/daemon/transport.js.map +1 -0
- package/esm/features.d.ts +10 -7
- package/esm/features.d.ts.map +1 -1
- package/esm/features.js +13 -10
- package/esm/features.js.map +1 -1
- package/esm/index.d.ts +7 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +7 -9
- package/esm/index.js.map +1 -1
- package/esm/server/client.d.ts +78 -0
- package/esm/server/client.d.ts.map +1 -0
- package/esm/server/client.js +329 -0
- package/esm/server/client.js.map +1 -0
- package/esm/server/index.d.ts +3 -0
- package/esm/server/index.d.ts.map +1 -0
- package/esm/server/index.js +3 -0
- package/esm/server/index.js.map +1 -0
- package/esm/server/transport.d.ts +19 -0
- package/esm/server/transport.d.ts.map +1 -0
- package/esm/server/transport.js +44 -0
- package/esm/server/transport.js.map +1 -0
- package/esm/utils/auto-reset-event.d.ts +8 -9
- package/esm/utils/auto-reset-event.d.ts.map +1 -1
- package/esm/utils/auto-reset-event.js +33 -33
- package/esm/utils/auto-reset-event.js.map +1 -1
- package/esm/utils/base64.d.ts +27 -27
- package/esm/utils/base64.js +246 -246
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +8 -0
- package/esm/utils/conditional-variable.d.ts.map +1 -0
- package/esm/utils/conditional-variable.js +34 -0
- package/esm/utils/conditional-variable.js.map +1 -0
- package/esm/utils/hex.d.ts +3 -0
- package/esm/utils/hex.d.ts.map +1 -0
- package/esm/utils/hex.js +55 -0
- package/esm/utils/hex.js.map +1 -0
- package/esm/utils/index.d.ts +6 -3
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +6 -3
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/no-op.d.ts +7 -0
- package/esm/utils/no-op.d.ts.map +1 -0
- package/esm/utils/no-op.js +12 -0
- package/esm/utils/no-op.js.map +1 -0
- package/package.json +14 -12
- package/src/adb.ts +47 -248
- package/src/banner.ts +82 -0
- package/src/commands/base.ts +1 -1
- package/src/commands/framebuffer.ts +4 -4
- package/src/commands/index.ts +7 -8
- package/src/commands/power.ts +2 -2
- package/src/commands/reverse.ts +90 -70
- package/src/commands/subprocess/command.ts +12 -4
- package/src/commands/subprocess/index.ts +3 -3
- package/src/commands/subprocess/protocols/index.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +36 -23
- package/src/commands/subprocess/protocols/shell.ts +94 -74
- package/src/commands/subprocess/protocols/types.ts +7 -7
- package/src/commands/subprocess/utils.ts +1 -1
- package/src/commands/sync/index.ts +8 -7
- package/src/commands/sync/list.ts +44 -25
- package/src/commands/sync/pull.ts +40 -45
- package/src/commands/sync/push.ts +158 -39
- package/src/commands/sync/request.ts +21 -16
- package/src/commands/sync/response.ts +10 -9
- package/src/commands/sync/socket.ts +99 -0
- package/src/commands/sync/stat.ts +47 -42
- package/src/commands/sync/sync.ts +73 -116
- package/src/commands/tcpip.ts +9 -7
- package/src/{auth.ts → daemon/auth.ts} +24 -23
- package/src/{crypto.ts → daemon/crypto.ts} +25 -33
- package/src/daemon/device.ts +14 -0
- package/src/{socket → daemon}/dispatcher.ts +95 -117
- package/src/daemon/index.ts +7 -0
- package/src/daemon/packet.ts +75 -0
- package/src/{socket → daemon}/socket.ts +71 -56
- package/src/daemon/transport.ts +269 -0
- package/src/features.ts +9 -6
- package/src/index.ts +3 -5
- package/src/server/client.ts +476 -0
- package/src/server/index.ts +2 -0
- package/src/server/transport.ts +77 -0
- package/src/utils/auto-reset-event.ts +14 -15
- package/src/utils/conditional-variable.ts +45 -0
- package/src/utils/hex.ts +58 -0
- package/src/utils/index.ts +6 -3
- package/src/utils/no-op.ts +12 -0
- package/tsconfig.build.json +12 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/auth.d.ts.map +0 -1
- package/esm/auth.js.map +0 -1
- package/esm/backend.d.ts +0 -9
- package/esm/backend.d.ts.map +0 -1
- package/esm/backend.js +0 -2
- package/esm/backend.js.map +0 -1
- package/esm/commands/install.d.ts +0 -4
- package/esm/commands/install.d.ts.map +0 -1
- package/esm/commands/install.js +0 -29
- package/esm/commands/install.js.map +0 -1
- package/esm/crypto.d.ts.map +0 -1
- package/esm/crypto.js.map +0 -1
- package/esm/packet.d.ts.map +0 -1
- package/esm/packet.js.map +0 -1
- package/esm/socket/dispatcher.d.ts +0 -60
- package/esm/socket/dispatcher.d.ts.map +0 -1
- package/esm/socket/dispatcher.js.map +0 -1
- package/esm/socket/index.d.ts +0 -3
- package/esm/socket/index.d.ts.map +0 -1
- package/esm/socket/index.js +0 -3
- package/esm/socket/index.js.map +0 -1
- package/esm/socket/socket.d.ts +0 -60
- package/esm/socket/socket.d.ts.map +0 -1
- package/esm/socket/socket.js.map +0 -1
- package/src/backend.ts +0 -14
- package/src/commands/install.ts +0 -40
- package/src/packet.ts +0 -90
- package/src/socket/index.ts +0 -2
|
@@ -1,22 +1,16 @@
|
|
|
1
1
|
import { AutoDisposable } from "@yume-chan/event";
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
type ReadableStream,
|
|
7
|
-
type WritableStream,
|
|
8
|
-
type WritableStreamDefaultWriter,
|
|
9
|
-
} from "@yume-chan/stream-extra";
|
|
10
|
-
|
|
11
|
-
import { type Adb } from "../../adb.js";
|
|
12
|
-
import { AdbFeatures } from "../../features.js";
|
|
13
|
-
import { type AdbSocket } from "../../socket/index.js";
|
|
14
|
-
import { AutoResetEvent } from "../../utils/index.js";
|
|
2
|
+
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
3
|
+
|
|
4
|
+
import type { Adb, AdbSocket } from "../../adb.js";
|
|
5
|
+
import { AdbFeature } from "../../features.js";
|
|
15
6
|
import { escapeArg } from "../subprocess/index.js";
|
|
16
7
|
|
|
17
|
-
import {
|
|
8
|
+
import type { AdbSyncEntry } from "./list.js";
|
|
9
|
+
import { adbSyncOpenDir } from "./list.js";
|
|
18
10
|
import { adbSyncPull } from "./pull.js";
|
|
19
11
|
import { adbSyncPush } from "./push.js";
|
|
12
|
+
import { AdbSyncSocket } from "./socket.js";
|
|
13
|
+
import type { AdbSyncStat, LinuxFileType } from "./stat.js";
|
|
20
14
|
import { adbSyncLstat, adbSyncStat } from "./stat.js";
|
|
21
15
|
|
|
22
16
|
/**
|
|
@@ -35,57 +29,65 @@ export function dirname(path: string): string {
|
|
|
35
29
|
return path.substring(0, end);
|
|
36
30
|
}
|
|
37
31
|
|
|
32
|
+
export interface AdbSyncWriteOptions {
|
|
33
|
+
filename: string;
|
|
34
|
+
file: ReadableStream<Consumable<Uint8Array>>;
|
|
35
|
+
type?: LinuxFileType;
|
|
36
|
+
permission?: number;
|
|
37
|
+
mtime?: number;
|
|
38
|
+
dryRun?: boolean;
|
|
39
|
+
}
|
|
40
|
+
|
|
38
41
|
export class AdbSync extends AutoDisposable {
|
|
39
|
-
protected
|
|
42
|
+
protected _adb: Adb;
|
|
43
|
+
protected _socket: AdbSyncSocket;
|
|
40
44
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
protected sendLock = this.addDisposable(new AutoResetEvent());
|
|
45
|
+
readonly #supportsStat: boolean;
|
|
46
|
+
readonly #supportsListV2: boolean;
|
|
47
|
+
readonly #fixedPushMkdir: boolean;
|
|
48
|
+
readonly #supportsSendReceiveV2: boolean;
|
|
49
|
+
readonly #needPushMkdirWorkaround: boolean;
|
|
47
50
|
|
|
48
51
|
public get supportsStat(): boolean {
|
|
49
|
-
return this
|
|
52
|
+
return this.#supportsStat;
|
|
50
53
|
}
|
|
51
54
|
|
|
52
|
-
public get
|
|
53
|
-
return this
|
|
55
|
+
public get supportsListV2(): boolean {
|
|
56
|
+
return this.#supportsListV2;
|
|
54
57
|
}
|
|
55
58
|
|
|
56
59
|
public get fixedPushMkdir(): boolean {
|
|
57
|
-
return this
|
|
60
|
+
return this.#fixedPushMkdir;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public get supportsSendReceiveV2(): boolean {
|
|
64
|
+
return this.#supportsSendReceiveV2;
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
public get needPushMkdirWorkaround(): boolean {
|
|
61
|
-
|
|
62
|
-
return (
|
|
63
|
-
this.adb.features.includes(AdbFeatures.ShellV2) &&
|
|
64
|
-
!this.fixedPushMkdir
|
|
65
|
-
);
|
|
68
|
+
return this.#needPushMkdirWorkaround;
|
|
66
69
|
}
|
|
67
70
|
|
|
68
71
|
public constructor(adb: Adb, socket: AdbSocket) {
|
|
69
72
|
super();
|
|
70
73
|
|
|
71
|
-
this.
|
|
72
|
-
this.
|
|
73
|
-
this.writer = socket.writable.getWriter();
|
|
74
|
-
}
|
|
74
|
+
this._adb = adb;
|
|
75
|
+
this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
77
|
+
this.#supportsStat = adb.supportsFeature(AdbFeature.StatV2);
|
|
78
|
+
this.#supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
|
|
79
|
+
this.#fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
|
|
80
|
+
this.#supportsSendReceiveV2 = adb.supportsFeature(
|
|
81
|
+
AdbFeature.SendReceiveV2
|
|
82
|
+
);
|
|
83
|
+
// https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
|
|
84
|
+
this.#needPushMkdirWorkaround =
|
|
85
|
+
this._adb.supportsFeature(AdbFeature.ShellV2) &&
|
|
86
|
+
!this.fixedPushMkdir;
|
|
87
|
+
}
|
|
78
88
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
this.stream,
|
|
82
|
-
this.writer,
|
|
83
|
-
path,
|
|
84
|
-
this.supportsStat
|
|
85
|
-
);
|
|
86
|
-
} finally {
|
|
87
|
-
this.sendLock.notify();
|
|
88
|
-
}
|
|
89
|
+
public async lstat(path: string): Promise<AdbSyncStat> {
|
|
90
|
+
return await adbSyncLstat(this._socket, path, this.supportsStat);
|
|
89
91
|
}
|
|
90
92
|
|
|
91
93
|
public async stat(path: string) {
|
|
@@ -93,13 +95,7 @@ export class AdbSync extends AutoDisposable {
|
|
|
93
95
|
throw new Error("Not supported");
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
await this.
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
return adbSyncStat(this.stream, this.writer, path);
|
|
100
|
-
} finally {
|
|
101
|
-
this.sendLock.notify();
|
|
102
|
-
}
|
|
98
|
+
return await adbSyncStat(this._socket, path);
|
|
103
99
|
}
|
|
104
100
|
|
|
105
101
|
public async isDirectory(path: string): Promise<boolean> {
|
|
@@ -111,21 +107,8 @@ export class AdbSync extends AutoDisposable {
|
|
|
111
107
|
}
|
|
112
108
|
}
|
|
113
109
|
|
|
114
|
-
public
|
|
115
|
-
path
|
|
116
|
-
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
117
|
-
await this.sendLock.wait();
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
yield* adbSyncOpenDir(
|
|
121
|
-
this.stream,
|
|
122
|
-
this.writer,
|
|
123
|
-
path,
|
|
124
|
-
this.supportsList2
|
|
125
|
-
);
|
|
126
|
-
} finally {
|
|
127
|
-
this.sendLock.notify();
|
|
128
|
-
}
|
|
110
|
+
public opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
111
|
+
return adbSyncOpenDir(this._socket, path, this.supportsListV2);
|
|
129
112
|
}
|
|
130
113
|
|
|
131
114
|
public async readdir(path: string) {
|
|
@@ -137,67 +120,41 @@ export class AdbSync extends AutoDisposable {
|
|
|
137
120
|
}
|
|
138
121
|
|
|
139
122
|
/**
|
|
140
|
-
*
|
|
123
|
+
* Reads the content of a file on device.
|
|
141
124
|
*
|
|
142
125
|
* @param filename The full path of the file on device to read.
|
|
143
|
-
* @returns A `ReadableStream` that
|
|
126
|
+
* @returns A `ReadableStream` that contains the file content.
|
|
144
127
|
*/
|
|
145
128
|
public read(filename: string): ReadableStream<Uint8Array> {
|
|
146
|
-
return
|
|
147
|
-
start: async () => {
|
|
148
|
-
await this.sendLock.wait();
|
|
149
|
-
return adbSyncPull(this.stream, this.writer, filename);
|
|
150
|
-
},
|
|
151
|
-
close: () => {
|
|
152
|
-
this.sendLock.notify();
|
|
153
|
-
},
|
|
154
|
-
});
|
|
129
|
+
return adbSyncPull(this._socket, filename);
|
|
155
130
|
}
|
|
156
131
|
|
|
157
132
|
/**
|
|
158
|
-
*
|
|
133
|
+
* Writes a file on device. If the file name already exists, it will be overwritten.
|
|
159
134
|
*
|
|
160
|
-
* @param
|
|
161
|
-
* @param mode The unix permissions of the file.
|
|
162
|
-
* @param mtime The modified time of the file.
|
|
163
|
-
* @returns A `WritableStream` that writes to the file.
|
|
135
|
+
* @param options The content and options of the file to write.
|
|
164
136
|
*/
|
|
165
|
-
public write(
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
escapeArg(dirname(filename)),
|
|
182
|
-
]);
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
return adbSyncPush(
|
|
186
|
-
this.stream,
|
|
187
|
-
this.writer,
|
|
188
|
-
filename,
|
|
189
|
-
mode,
|
|
190
|
-
mtime
|
|
191
|
-
);
|
|
192
|
-
},
|
|
193
|
-
close: () => {
|
|
194
|
-
this.sendLock.notify();
|
|
195
|
-
},
|
|
137
|
+
public async write(options: AdbSyncWriteOptions): Promise<void> {
|
|
138
|
+
if (this.needPushMkdirWorkaround) {
|
|
139
|
+
// It may fail if the path is already existed.
|
|
140
|
+
// Ignore the result.
|
|
141
|
+
// TODO: sync: test push mkdir workaround (need an Android 8 device)
|
|
142
|
+
await this._adb.subprocess.spawnAndWait([
|
|
143
|
+
"mkdir",
|
|
144
|
+
"-p",
|
|
145
|
+
escapeArg(dirname(options.filename)),
|
|
146
|
+
]);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
await adbSyncPush({
|
|
150
|
+
v2: this.supportsSendReceiveV2,
|
|
151
|
+
socket: this._socket,
|
|
152
|
+
...options,
|
|
196
153
|
});
|
|
197
154
|
}
|
|
198
155
|
|
|
199
156
|
public override async dispose() {
|
|
200
157
|
super.dispose();
|
|
201
|
-
await this.
|
|
158
|
+
await this._socket.close();
|
|
202
159
|
}
|
|
203
160
|
}
|
package/src/commands/tcpip.ts
CHANGED
|
@@ -1,21 +1,23 @@
|
|
|
1
|
-
import { AdbCommandBase } from
|
|
1
|
+
import { AdbCommandBase } from "./base.js";
|
|
2
2
|
|
|
3
3
|
export class AdbTcpIpCommand extends AdbCommandBase {
|
|
4
|
-
public async setPort(port: number): Promise<
|
|
4
|
+
public async setPort(port: number): Promise<string> {
|
|
5
5
|
if (port <= 0) {
|
|
6
6
|
throw new Error(`Invalid port ${port}`);
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
const output = await this.adb.createSocketAndWait(`tcpip:${port}`);
|
|
10
10
|
if (output !== `restarting in TCP mode port: ${port}\n`) {
|
|
11
|
-
throw new Error(
|
|
11
|
+
throw new Error(output);
|
|
12
12
|
}
|
|
13
|
+
return output;
|
|
13
14
|
}
|
|
14
15
|
|
|
15
|
-
public async disable(): Promise<
|
|
16
|
-
const output = await this.adb.createSocketAndWait(
|
|
17
|
-
if (output !==
|
|
18
|
-
throw new Error(
|
|
16
|
+
public async disable(): Promise<string> {
|
|
17
|
+
const output = await this.adb.createSocketAndWait("usb:");
|
|
18
|
+
if (output !== "restarting in USB mode\n") {
|
|
19
|
+
throw new Error(output);
|
|
19
20
|
}
|
|
21
|
+
return output;
|
|
20
22
|
}
|
|
21
23
|
}
|
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
import { PromiseResolver } from "@yume-chan/async";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import type { Disposable } from "@yume-chan/event";
|
|
3
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
4
|
+
|
|
5
|
+
import { calculateBase64EncodedLength, encodeBase64 } from "../utils/index.js";
|
|
4
6
|
|
|
5
7
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
8
|
+
adbGeneratePublicKey,
|
|
9
|
+
adbGetPublicKeySize,
|
|
10
|
+
rsaSign,
|
|
9
11
|
} from "./crypto.js";
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
+
import type { AdbPacketData } from "./packet.js";
|
|
13
|
+
import { AdbCommand } from "./packet.js";
|
|
12
14
|
|
|
13
15
|
export type AdbKeyIterable = Iterable<Uint8Array> | AsyncIterable<Uint8Array>;
|
|
14
16
|
|
|
@@ -63,7 +65,7 @@ export const AdbSignatureAuthenticator: AdbAuthenticator = async function* (
|
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
|
|
66
|
-
const signature =
|
|
68
|
+
const signature = rsaSign(key, packet.payload);
|
|
67
69
|
yield {
|
|
68
70
|
command: AdbCommand.Auth,
|
|
69
71
|
arg0: AdbAuthType.Signature,
|
|
@@ -93,15 +95,15 @@ export const AdbPublicKeyAuthenticator: AdbAuthenticator = async function* (
|
|
|
93
95
|
privateKey = await credentialStore.generateKey();
|
|
94
96
|
}
|
|
95
97
|
|
|
96
|
-
const publicKeyLength =
|
|
98
|
+
const publicKeyLength = adbGetPublicKeySize();
|
|
97
99
|
const [publicKeyBase64Length] =
|
|
98
100
|
calculateBase64EncodedLength(publicKeyLength);
|
|
99
101
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
const publicKeyBuffer = new Uint8Array(
|
|
103
|
+
publicKeyBase64Length + 1 // Null character
|
|
104
|
+
);
|
|
103
105
|
|
|
104
|
-
|
|
106
|
+
adbGeneratePublicKey(privateKey, publicKeyBuffer);
|
|
105
107
|
encodeBase64(publicKeyBuffer.subarray(0, publicKeyLength), publicKeyBuffer);
|
|
106
108
|
|
|
107
109
|
yield {
|
|
@@ -122,9 +124,8 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
122
124
|
|
|
123
125
|
private readonly credentialStore: AdbCredentialStore;
|
|
124
126
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
private iterator: AsyncIterator<AdbPacketData, void, void> | undefined;
|
|
127
|
+
#pendingRequest = new PromiseResolver<AdbPacketData>();
|
|
128
|
+
#iterator: AsyncIterator<AdbPacketData, void, void> | undefined;
|
|
128
129
|
|
|
129
130
|
public constructor(
|
|
130
131
|
authenticators: readonly AdbAuthenticator[],
|
|
@@ -135,7 +136,7 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
135
136
|
}
|
|
136
137
|
|
|
137
138
|
private getNextRequest = (): Promise<AdbPacketData> => {
|
|
138
|
-
return this
|
|
139
|
+
return this.#pendingRequest.promise;
|
|
139
140
|
};
|
|
140
141
|
|
|
141
142
|
private async *invokeAuthenticator(): AsyncGenerator<
|
|
@@ -150,7 +151,7 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
150
151
|
)) {
|
|
151
152
|
// If the authenticator yielded a response
|
|
152
153
|
// Prepare `nextRequest` for next authentication request
|
|
153
|
-
this
|
|
154
|
+
this.#pendingRequest = new PromiseResolver();
|
|
154
155
|
|
|
155
156
|
// Yield the response to outer layer
|
|
156
157
|
yield packet;
|
|
@@ -162,13 +163,13 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
162
163
|
}
|
|
163
164
|
|
|
164
165
|
public async process(packet: AdbPacketData): Promise<AdbPacketData> {
|
|
165
|
-
if (!this
|
|
166
|
-
this
|
|
166
|
+
if (!this.#iterator) {
|
|
167
|
+
this.#iterator = this.invokeAuthenticator();
|
|
167
168
|
}
|
|
168
169
|
|
|
169
|
-
this
|
|
170
|
+
this.#pendingRequest.resolve(packet);
|
|
170
171
|
|
|
171
|
-
const result = await this
|
|
172
|
+
const result = await this.#iterator.next();
|
|
172
173
|
if (result.done) {
|
|
173
174
|
throw new Error("No authenticator can handle the request");
|
|
174
175
|
}
|
|
@@ -177,6 +178,6 @@ export class AdbAuthenticationProcessor implements Disposable {
|
|
|
177
178
|
}
|
|
178
179
|
|
|
179
180
|
public dispose() {
|
|
180
|
-
void this
|
|
181
|
+
void this.#iterator?.return?.();
|
|
181
182
|
}
|
|
182
183
|
}
|
|
@@ -3,11 +3,6 @@ import {
|
|
|
3
3
|
setBigUint64,
|
|
4
4
|
} from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
|
|
5
5
|
|
|
6
|
-
const BigInt0 = BigInt(0);
|
|
7
|
-
const BigInt1 = BigInt(1);
|
|
8
|
-
const BigInt2 = BigInt(2);
|
|
9
|
-
const BigInt64 = BigInt(64);
|
|
10
|
-
|
|
11
6
|
/**
|
|
12
7
|
* Gets the `BigInt` value at the specified byte offset and length from the start of the view. There is
|
|
13
8
|
* no alignment constraint; multi-byte values may be fetched from any offset.
|
|
@@ -20,13 +15,13 @@ export function getBigUint(
|
|
|
20
15
|
byteOffset: number,
|
|
21
16
|
length: number
|
|
22
17
|
): bigint {
|
|
23
|
-
let result =
|
|
18
|
+
let result = 0n;
|
|
24
19
|
|
|
25
20
|
// Currently `length` must be a multiplication of 8
|
|
26
21
|
// Support for arbitrary length can be easily added
|
|
27
22
|
|
|
28
23
|
for (let i = byteOffset; i < byteOffset + length; i += 8) {
|
|
29
|
-
result <<=
|
|
24
|
+
result <<= 64n;
|
|
30
25
|
const value = getBigUint64(dataView, i, false);
|
|
31
26
|
result += value;
|
|
32
27
|
}
|
|
@@ -50,18 +45,18 @@ export function setBigUint(
|
|
|
50
45
|
const start = byteOffset;
|
|
51
46
|
|
|
52
47
|
if (littleEndian) {
|
|
53
|
-
while (value >
|
|
48
|
+
while (value > 0n) {
|
|
54
49
|
setBigUint64(dataView, byteOffset, value, true);
|
|
55
50
|
byteOffset += 8;
|
|
56
|
-
value >>=
|
|
51
|
+
value >>= 64n;
|
|
57
52
|
}
|
|
58
53
|
} else {
|
|
59
54
|
// Because we don't know how long (in bits) the `value` is,
|
|
60
55
|
// Convert it to an array of `uint64` first.
|
|
61
56
|
const uint64Array: bigint[] = [];
|
|
62
|
-
while (value >
|
|
57
|
+
while (value > 0n) {
|
|
63
58
|
uint64Array.push(BigInt.asUintN(64, value));
|
|
64
|
-
value >>=
|
|
59
|
+
value >>= 64n;
|
|
65
60
|
}
|
|
66
61
|
|
|
67
62
|
for (let i = uint64Array.length - 1; i >= 0; i -= 1) {
|
|
@@ -99,7 +94,7 @@ const RsaPrivateKeyNLength = 2048 / 8;
|
|
|
99
94
|
const RsaPrivateKeyDOffset = 303;
|
|
100
95
|
const RsaPrivateKeyDLength = 2048 / 8;
|
|
101
96
|
|
|
102
|
-
export function
|
|
97
|
+
export function rsaParsePrivateKey(key: Uint8Array): [n: bigint, d: bigint] {
|
|
103
98
|
const view = new DataView(key.buffer, key.byteOffset, key.byteLength);
|
|
104
99
|
const n = getBigUint(view, RsaPrivateKeyNOffset, RsaPrivateKeyNLength);
|
|
105
100
|
const d = getBigUint(view, RsaPrivateKeyDOffset, RsaPrivateKeyDLength);
|
|
@@ -133,16 +128,16 @@ export function modInverse(a: number, m: number) {
|
|
|
133
128
|
return ((y % m) + m) % m;
|
|
134
129
|
}
|
|
135
130
|
|
|
136
|
-
export function
|
|
131
|
+
export function adbGetPublicKeySize() {
|
|
137
132
|
return 4 + 4 + 2048 / 8 + 2048 / 8 + 4;
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
export function
|
|
141
|
-
export function
|
|
135
|
+
export function adbGeneratePublicKey(privateKey: Uint8Array): Uint8Array;
|
|
136
|
+
export function adbGeneratePublicKey(
|
|
142
137
|
privateKey: Uint8Array,
|
|
143
138
|
output: Uint8Array
|
|
144
139
|
): number;
|
|
145
|
-
export function
|
|
140
|
+
export function adbGeneratePublicKey(
|
|
146
141
|
privateKey: Uint8Array,
|
|
147
142
|
output?: Uint8Array
|
|
148
143
|
): Uint8Array | number {
|
|
@@ -164,10 +159,10 @@ export function calculatePublicKey(
|
|
|
164
159
|
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#38
|
|
165
160
|
|
|
166
161
|
// extract `n` from private key
|
|
167
|
-
const [n] =
|
|
162
|
+
const [n] = rsaParsePrivateKey(privateKey);
|
|
168
163
|
|
|
169
164
|
let outputType: "Uint8Array" | "number";
|
|
170
|
-
const outputLength =
|
|
165
|
+
const outputLength = adbGetPublicKeySize();
|
|
171
166
|
if (!output) {
|
|
172
167
|
output = new Uint8Array(outputLength);
|
|
173
168
|
outputType = "Uint8Array";
|
|
@@ -191,12 +186,9 @@ export function calculatePublicKey(
|
|
|
191
186
|
outputOffset += 4;
|
|
192
187
|
|
|
193
188
|
// Calculate `n0inv`
|
|
194
|
-
// Don't know why need to
|
|
189
|
+
// Don't know why need to multiply by -1
|
|
195
190
|
// Didn't exist in Android codebase
|
|
196
|
-
const n0inv = modInverse(
|
|
197
|
-
Number(BigInt.asUintN(32, n) * BigInt(-1)),
|
|
198
|
-
2 ** 32
|
|
199
|
-
);
|
|
191
|
+
const n0inv = modInverse(-Number(BigInt.asUintN(32, n)), 2 ** 32);
|
|
200
192
|
outputView.setUint32(outputOffset, n0inv, true);
|
|
201
193
|
outputOffset += 4;
|
|
202
194
|
|
|
@@ -205,7 +197,7 @@ export function calculatePublicKey(
|
|
|
205
197
|
outputOffset += 256;
|
|
206
198
|
|
|
207
199
|
// Calculate rr = (2^(rsa_size)) ^ 2 mod n
|
|
208
|
-
const rr =
|
|
200
|
+
const rr = 2n ** 4096n % n;
|
|
209
201
|
outputOffset += setBigUint(outputView, outputOffset, rr, true);
|
|
210
202
|
|
|
211
203
|
// exponent
|
|
@@ -231,20 +223,20 @@ export function powMod(
|
|
|
231
223
|
exponent: bigint,
|
|
232
224
|
modulus: bigint
|
|
233
225
|
): bigint {
|
|
234
|
-
if (modulus ===
|
|
235
|
-
return
|
|
226
|
+
if (modulus === 1n) {
|
|
227
|
+
return 0n;
|
|
236
228
|
}
|
|
237
229
|
|
|
238
|
-
let r =
|
|
230
|
+
let r = 1n;
|
|
239
231
|
base = base % modulus;
|
|
240
232
|
|
|
241
|
-
while (exponent >
|
|
242
|
-
if (BigInt.asUintN(1, exponent) ===
|
|
233
|
+
while (exponent > 0n) {
|
|
234
|
+
if (BigInt.asUintN(1, exponent) === 1n) {
|
|
243
235
|
r = (r * base) % modulus;
|
|
244
236
|
}
|
|
245
237
|
|
|
246
|
-
|
|
247
|
-
|
|
238
|
+
base = (base * base) % modulus;
|
|
239
|
+
exponent >>= 1n;
|
|
248
240
|
}
|
|
249
241
|
|
|
250
242
|
return r;
|
|
@@ -283,8 +275,8 @@ export const SHA1_DIGEST_INFO = new Uint8Array([
|
|
|
283
275
|
// encrypt the given data with its private key)
|
|
284
276
|
// However SubtileCrypto.encrypt() doesn't accept 'RSASSA-PKCS1-v1_5' algorithm
|
|
285
277
|
// So we need to implement the encryption by ourself
|
|
286
|
-
export function
|
|
287
|
-
const [n, d] =
|
|
278
|
+
export function rsaSign(privateKey: Uint8Array, data: Uint8Array): Uint8Array {
|
|
279
|
+
const [n, d] = rsaParsePrivateKey(privateKey);
|
|
288
280
|
|
|
289
281
|
// PKCS#1 padding
|
|
290
282
|
const padded = new Uint8Array(256);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Consumable, ReadableWritablePair } from "@yume-chan/stream-extra";
|
|
2
|
+
import type { ValueOrPromise } from "@yume-chan/struct";
|
|
3
|
+
|
|
4
|
+
import type { AdbPacketData, AdbPacketInit } from "./packet.js";
|
|
5
|
+
|
|
6
|
+
export interface AdbDaemonDevice {
|
|
7
|
+
readonly serial: string;
|
|
8
|
+
|
|
9
|
+
readonly name: string | undefined;
|
|
10
|
+
|
|
11
|
+
connect(): ValueOrPromise<
|
|
12
|
+
ReadableWritablePair<AdbPacketData, Consumable<AdbPacketInit>>
|
|
13
|
+
>;
|
|
14
|
+
}
|