@yume-chan/adb 0.0.17 → 0.0.19
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 +27 -0
- package/CHANGELOG.md +16 -1
- package/LICENSE +1 -1
- package/esm/adb.d.ts +63 -60
- package/esm/adb.d.ts.map +1 -1
- package/esm/adb.js +257 -229
- package/esm/adb.js.map +1 -1
- package/esm/auth.d.ts +51 -51
- package/esm/auth.d.ts.map +1 -1
- package/esm/auth.js +95 -96
- package/esm/auth.js.map +1 -1
- package/esm/backend.d.ts +8 -8
- package/esm/backend.d.ts.map +1 -1
- package/esm/backend.js +1 -1
- package/esm/commands/base.d.ts +6 -6
- 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 -47
- 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/install.d.ts +9 -3
- package/esm/commands/install.d.ts.map +1 -1
- package/esm/commands/install.js +27 -21
- package/esm/commands/install.js.map +1 -1
- package/esm/commands/power.d.ts +22 -22
- package/esm/commands/power.d.ts.map +1 -1
- package/esm/commands/power.js +48 -44
- package/esm/commands/power.js.map +1 -1
- package/esm/commands/reverse.d.ts +41 -28
- package/esm/commands/reverse.d.ts.map +1 -1
- package/esm/commands/reverse.js +125 -98
- 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 -82
- 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 +35 -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 +39 -38
- package/esm/commands/subprocess/protocols/shell.d.ts.map +1 -1
- package/esm/commands/subprocess/protocols/shell.js +166 -154
- package/esm/commands/subprocess/protocols/shell.js.map +1 -1
- package/esm/commands/subprocess/protocols/types.d.ts +49 -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 -35
- 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 -36
- package/esm/commands/sync/pull.js.map +1 -1
- package/esm/commands/sync/push.d.ts +46 -7
- package/esm/commands/sync/push.d.ts.map +1 -1
- package/esm/commands/sync/push.js +89 -23
- 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 +27 -0
- package/esm/commands/sync/socket.d.ts.map +1 -0
- package/esm/commands/sync/socket.js +66 -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 -94
- package/esm/commands/sync/stat.js.map +1 -1
- package/esm/commands/sync/sync.d.ts +72 -60
- package/esm/commands/sync/sync.d.ts.map +1 -1
- package/esm/commands/sync/sync.js +127 -148
- package/esm/commands/sync/sync.js.map +1 -1
- package/esm/commands/tcpip.d.ts +5 -5
- package/esm/commands/tcpip.js +18 -18
- package/esm/crypto.d.ts +36 -36
- package/esm/crypto.d.ts.map +1 -1
- package/esm/crypto.js +248 -238
- package/esm/crypto.js.map +1 -1
- 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 +9 -9
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +9 -9
- package/esm/index.js.map +1 -1
- package/esm/packet.d.ts +45 -46
- package/esm/packet.d.ts.map +1 -1
- package/esm/packet.js +43 -46
- package/esm/packet.js.map +1 -1
- package/esm/socket/dispatcher.d.ts +59 -59
- package/esm/socket/dispatcher.d.ts.map +1 -1
- package/esm/socket/dispatcher.js +223 -231
- package/esm/socket/dispatcher.js.map +1 -1
- package/esm/socket/index.d.ts +2 -2
- package/esm/socket/index.js +2 -2
- package/esm/socket/socket.d.ts +59 -59
- package/esm/socket/socket.d.ts.map +1 -1
- package/esm/socket/socket.js +118 -98
- package/esm/socket/socket.js.map +1 -1
- package/esm/utils/auto-reset-event.d.ts +9 -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.d.ts.map +1 -1
- package/esm/utils/base64.js +246 -245
- package/esm/utils/base64.js.map +1 -1
- package/esm/utils/conditional-variable.d.ts +9 -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/index.d.ts +4 -3
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +4 -3
- package/esm/utils/index.js.map +1 -1
- package/package.json +17 -13
- package/src/adb.ts +160 -101
- package/src/auth.ts +31 -22
- package/src/backend.ts +6 -4
- package/src/commands/base.ts +2 -2
- package/src/commands/framebuffer.ts +37 -41
- package/src/commands/index.ts +7 -8
- package/src/commands/power.ts +15 -11
- package/src/commands/reverse.ts +74 -30
- package/src/commands/subprocess/command.ts +34 -23
- package/src/commands/subprocess/index.ts +3 -3
- package/src/commands/subprocess/protocols/index.ts +3 -3
- package/src/commands/subprocess/protocols/none.ts +26 -11
- package/src/commands/subprocess/protocols/shell.ts +110 -56
- package/src/commands/subprocess/protocols/types.ts +10 -6
- package/src/commands/subprocess/utils.ts +1 -1
- package/src/commands/sync/index.ts +8 -7
- package/src/commands/sync/list.ts +74 -28
- package/src/commands/sync/pull.ts +49 -37
- package/src/commands/sync/push.ts +153 -32
- package/src/commands/sync/request.ts +37 -34
- package/src/commands/sync/response.ts +34 -27
- package/src/commands/sync/socket.ts +97 -0
- package/src/commands/sync/stat.ts +98 -70
- package/src/commands/sync/sync.ts +78 -97
- package/src/commands/tcpip.ts +5 -5
- package/src/crypto.ts +60 -32
- package/src/features.ts +9 -6
- package/src/index.ts +9 -10
- package/src/packet.ts +41 -46
- package/src/socket/dispatcher.ts +130 -108
- package/src/socket/index.ts +2 -2
- package/src/socket/socket.ts +84 -34
- package/src/utils/auto-reset-event.ts +16 -17
- package/src/utils/base64.ts +51 -41
- package/src/utils/conditional-variable.ts +45 -0
- package/src/utils/index.ts +4 -3
- package/tsconfig.build.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/src/commands/install.ts +0 -32
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { AutoDisposable } from
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
import type { Adb } from
|
|
5
|
-
import {
|
|
6
|
-
import type { AdbSocket } from
|
|
7
|
-
import {
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
1
|
+
import { AutoDisposable } from "@yume-chan/event";
|
|
2
|
+
import type { Consumable, ReadableStream } from "@yume-chan/stream-extra";
|
|
3
|
+
|
|
4
|
+
import type { Adb } from "../../adb.js";
|
|
5
|
+
import { AdbFeature } from "../../features.js";
|
|
6
|
+
import type { AdbSocket } from "../../socket/index.js";
|
|
7
|
+
import { escapeArg } from "../subprocess/index.js";
|
|
8
|
+
|
|
9
|
+
import type { AdbSyncEntry } from "./list.js";
|
|
10
|
+
import { adbSyncOpenDir } from "./list.js";
|
|
11
|
+
import { adbSyncPull } from "./pull.js";
|
|
12
|
+
import { adbSyncPush } from "./push.js";
|
|
13
|
+
import { AdbSyncSocket } from "./socket.js";
|
|
14
|
+
import { adbSyncLstat, adbSyncStat } from "./stat.js";
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* A simplified `dirname` function that only handles absolute unix paths.
|
|
@@ -17,94 +19,95 @@ import { adbSyncLstat, adbSyncStat } from './stat.js';
|
|
|
17
19
|
* @returns the directory name of the input path
|
|
18
20
|
*/
|
|
19
21
|
export function dirname(path: string): string {
|
|
20
|
-
const end = path.lastIndexOf(
|
|
22
|
+
const end = path.lastIndexOf("/");
|
|
21
23
|
if (end === -1) {
|
|
22
24
|
throw new Error(`Invalid path`);
|
|
23
25
|
}
|
|
24
26
|
if (end === 0) {
|
|
25
|
-
return
|
|
27
|
+
return "/";
|
|
26
28
|
}
|
|
27
29
|
return path.substring(0, end);
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
export interface AdbSyncWriteOptions {
|
|
33
|
+
filename: string;
|
|
34
|
+
file: ReadableStream<Consumable<Uint8Array>>;
|
|
35
|
+
mode?: number;
|
|
36
|
+
mtime?: number;
|
|
37
|
+
dryRun?: boolean;
|
|
38
|
+
}
|
|
39
|
+
|
|
30
40
|
export class AdbSync extends AutoDisposable {
|
|
31
|
-
protected
|
|
41
|
+
protected _adb: Adb;
|
|
42
|
+
protected _socket: AdbSyncSocket;
|
|
32
43
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
protected sendLock = this.addDisposable(new AutoResetEvent());
|
|
44
|
+
private _supportsStat: boolean;
|
|
45
|
+
private _supportsListV2: boolean;
|
|
46
|
+
private _fixedPushMkdir: boolean;
|
|
47
|
+
private _supportsSendReceiveV2: boolean;
|
|
48
|
+
private _needPushMkdirWorkaround: boolean;
|
|
39
49
|
|
|
40
50
|
public get supportsStat(): boolean {
|
|
41
|
-
return this.
|
|
51
|
+
return this._supportsStat;
|
|
42
52
|
}
|
|
43
53
|
|
|
44
|
-
public get
|
|
45
|
-
return this.
|
|
54
|
+
public get supportsListV2(): boolean {
|
|
55
|
+
return this._supportsListV2;
|
|
46
56
|
}
|
|
47
57
|
|
|
48
58
|
public get fixedPushMkdir(): boolean {
|
|
49
|
-
return this.
|
|
59
|
+
return this._fixedPushMkdir;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
public get supportsSendReceiveV2(): boolean {
|
|
63
|
+
return this._supportsSendReceiveV2;
|
|
50
64
|
}
|
|
51
65
|
|
|
52
66
|
public get needPushMkdirWorkaround(): boolean {
|
|
53
|
-
|
|
54
|
-
return this.adb.features.includes(AdbFeatures.ShellV2) && !this.fixedPushMkdir;
|
|
67
|
+
return this._needPushMkdirWorkaround;
|
|
55
68
|
}
|
|
56
69
|
|
|
57
70
|
public constructor(adb: Adb, socket: AdbSocket) {
|
|
58
71
|
super();
|
|
59
72
|
|
|
60
|
-
this.
|
|
61
|
-
this.
|
|
62
|
-
|
|
73
|
+
this._adb = adb;
|
|
74
|
+
this._socket = new AdbSyncSocket(socket, adb.maxPayloadSize);
|
|
75
|
+
|
|
76
|
+
this._supportsStat = adb.supportsFeature(AdbFeature.StatV2);
|
|
77
|
+
this._supportsListV2 = adb.supportsFeature(AdbFeature.ListV2);
|
|
78
|
+
this._fixedPushMkdir = adb.supportsFeature(AdbFeature.FixedPushMkdir);
|
|
79
|
+
this._supportsSendReceiveV2 = adb.supportsFeature(
|
|
80
|
+
AdbFeature.SendReceiveV2
|
|
81
|
+
);
|
|
82
|
+
// https://android.googlesource.com/platform/packages/modules/adb/+/91768a57b7138166e0a3d11f79cd55909dda7014/client/file_sync_client.cpp#1361
|
|
83
|
+
this._needPushMkdirWorkaround =
|
|
84
|
+
this._adb.supportsFeature(AdbFeature.ShellV2) &&
|
|
85
|
+
!this.fixedPushMkdir;
|
|
63
86
|
}
|
|
64
87
|
|
|
65
88
|
public async lstat(path: string) {
|
|
66
|
-
await this.
|
|
67
|
-
|
|
68
|
-
try {
|
|
69
|
-
return adbSyncLstat(this.stream, this.writer, path, this.supportsStat);
|
|
70
|
-
} finally {
|
|
71
|
-
this.sendLock.notify();
|
|
72
|
-
}
|
|
89
|
+
return await adbSyncLstat(this._socket, path, this.supportsStat);
|
|
73
90
|
}
|
|
74
91
|
|
|
75
92
|
public async stat(path: string) {
|
|
76
93
|
if (!this.supportsStat) {
|
|
77
|
-
throw new Error(
|
|
94
|
+
throw new Error("Not supported");
|
|
78
95
|
}
|
|
79
96
|
|
|
80
|
-
await this.
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
return adbSyncStat(this.stream, this.writer, path);
|
|
84
|
-
} finally {
|
|
85
|
-
this.sendLock.notify();
|
|
86
|
-
}
|
|
97
|
+
return await adbSyncStat(this._socket, path);
|
|
87
98
|
}
|
|
88
99
|
|
|
89
100
|
public async isDirectory(path: string): Promise<boolean> {
|
|
90
101
|
try {
|
|
91
|
-
await this.lstat(path +
|
|
102
|
+
await this.lstat(path + "/");
|
|
92
103
|
return true;
|
|
93
104
|
} catch (e) {
|
|
94
105
|
return false;
|
|
95
106
|
}
|
|
96
107
|
}
|
|
97
108
|
|
|
98
|
-
public
|
|
99
|
-
path
|
|
100
|
-
): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
101
|
-
await this.sendLock.wait();
|
|
102
|
-
|
|
103
|
-
try {
|
|
104
|
-
yield* adbSyncOpenDir(this.stream, this.writer, path, this.supportsList2);
|
|
105
|
-
} finally {
|
|
106
|
-
this.sendLock.notify();
|
|
107
|
-
}
|
|
109
|
+
public opendir(path: string): AsyncGenerator<AdbSyncEntry, void, void> {
|
|
110
|
+
return adbSyncOpenDir(this._socket, path, this.supportsListV2);
|
|
108
111
|
}
|
|
109
112
|
|
|
110
113
|
public async readdir(path: string) {
|
|
@@ -122,61 +125,39 @@ export class AdbSync extends AutoDisposable {
|
|
|
122
125
|
* @returns A `ReadableStream` that reads from the file.
|
|
123
126
|
*/
|
|
124
127
|
public read(filename: string): ReadableStream<Uint8Array> {
|
|
125
|
-
return
|
|
126
|
-
start: async () => {
|
|
127
|
-
await this.sendLock.wait();
|
|
128
|
-
return adbSyncPull(this.stream, this.writer, filename);
|
|
129
|
-
},
|
|
130
|
-
close: async () => {
|
|
131
|
-
this.sendLock.notify();
|
|
132
|
-
},
|
|
133
|
-
});
|
|
128
|
+
return adbSyncPull(this._socket, filename);
|
|
134
129
|
}
|
|
135
130
|
|
|
136
131
|
/**
|
|
137
132
|
* Write (or overwrite) a file on device.
|
|
138
133
|
*
|
|
139
134
|
* @param filename The full path of the file on device to write.
|
|
135
|
+
* @param file The content to write.
|
|
140
136
|
* @param mode The unix permissions of the file.
|
|
141
137
|
* @param mtime The modified time of the file.
|
|
142
138
|
* @returns A `WritableStream` that writes to the file.
|
|
143
139
|
*/
|
|
144
|
-
public write(
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
escapeArg(dirname(filename)),
|
|
161
|
-
]);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
return adbSyncPush(
|
|
165
|
-
this.stream,
|
|
166
|
-
this.writer,
|
|
167
|
-
filename,
|
|
168
|
-
mode,
|
|
169
|
-
mtime,
|
|
170
|
-
);
|
|
171
|
-
},
|
|
172
|
-
close: async () => {
|
|
173
|
-
this.sendLock.notify();
|
|
174
|
-
}
|
|
140
|
+
public async write(options: AdbSyncWriteOptions) {
|
|
141
|
+
if (this.needPushMkdirWorkaround) {
|
|
142
|
+
// It may fail if the path is already existed.
|
|
143
|
+
// Ignore the result.
|
|
144
|
+
// TODO: sync: test push mkdir workaround (need an Android 8 device)
|
|
145
|
+
await this._adb.subprocess.spawnAndWait([
|
|
146
|
+
"mkdir",
|
|
147
|
+
"-p",
|
|
148
|
+
escapeArg(dirname(options.filename)),
|
|
149
|
+
]);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
await adbSyncPush({
|
|
153
|
+
v2: this.supportsSendReceiveV2,
|
|
154
|
+
socket: this._socket,
|
|
155
|
+
...options,
|
|
175
156
|
});
|
|
176
157
|
}
|
|
177
158
|
|
|
178
159
|
public override async dispose() {
|
|
179
160
|
super.dispose();
|
|
180
|
-
await this.
|
|
161
|
+
await this._socket.close();
|
|
181
162
|
}
|
|
182
163
|
}
|
package/src/commands/tcpip.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AdbCommandBase } from
|
|
1
|
+
import { AdbCommandBase } from "./base.js";
|
|
2
2
|
|
|
3
3
|
export class AdbTcpIpCommand extends AdbCommandBase {
|
|
4
4
|
public async setPort(port: number): Promise<void> {
|
|
@@ -8,14 +8,14 @@ export class AdbTcpIpCommand extends AdbCommandBase {
|
|
|
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("Invalid response");
|
|
12
12
|
}
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
public async disable(): Promise<void> {
|
|
16
|
-
const output = await this.adb.createSocketAndWait(
|
|
17
|
-
if (output !==
|
|
18
|
-
throw new Error(
|
|
16
|
+
const output = await this.adb.createSocketAndWait("usb:");
|
|
17
|
+
if (output !== "restarting in USB mode\n") {
|
|
18
|
+
throw new Error("Invalid response");
|
|
19
19
|
}
|
|
20
20
|
}
|
|
21
21
|
}
|
package/src/crypto.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
getBigUint64,
|
|
3
|
+
setBigUint64,
|
|
4
|
+
} from "@yume-chan/dataview-bigint-polyfill/esm/fallback.js";
|
|
2
5
|
|
|
3
6
|
const BigInt0 = BigInt(0);
|
|
4
7
|
const BigInt1 = BigInt(1);
|
|
@@ -12,7 +15,11 @@ const BigInt64 = BigInt(64);
|
|
|
12
15
|
* Only supports Big-Endian, because that's what ADB uses.
|
|
13
16
|
* @param byteOffset The place in the buffer at which the value should be retrieved.
|
|
14
17
|
*/
|
|
15
|
-
export function getBigUint(
|
|
18
|
+
export function getBigUint(
|
|
19
|
+
dataView: DataView,
|
|
20
|
+
byteOffset: number,
|
|
21
|
+
length: number
|
|
22
|
+
): bigint {
|
|
16
23
|
let result = BigInt0;
|
|
17
24
|
|
|
18
25
|
// Currently `length` must be a multiplication of 8
|
|
@@ -34,7 +41,12 @@ export function getBigUint(dataView: DataView, byteOffset: number, length: numbe
|
|
|
34
41
|
* @param littleEndian If `false` or `undefined`, a big-endian value should be written,
|
|
35
42
|
* otherwise a little-endian value should be written.
|
|
36
43
|
*/
|
|
37
|
-
export function setBigUint(
|
|
44
|
+
export function setBigUint(
|
|
45
|
+
dataView: DataView,
|
|
46
|
+
byteOffset: number,
|
|
47
|
+
value: bigint,
|
|
48
|
+
littleEndian?: boolean
|
|
49
|
+
) {
|
|
38
50
|
const start = byteOffset;
|
|
39
51
|
|
|
40
52
|
if (littleEndian) {
|
|
@@ -98,7 +110,7 @@ export function parsePrivateKey(key: Uint8Array): [n: bigint, d: bigint] {
|
|
|
98
110
|
// I can't understand, but it does work
|
|
99
111
|
// Only used with numbers smaller than 2^32 so doesn't need BigInt
|
|
100
112
|
export function modInverse(a: number, m: number) {
|
|
101
|
-
a = (a % m + m) % m;
|
|
113
|
+
a = ((a % m) + m) % m;
|
|
102
114
|
if (!a || m < 2) {
|
|
103
115
|
return NaN; // invalid input
|
|
104
116
|
}
|
|
@@ -115,26 +127,24 @@ export function modInverse(a: number, m: number) {
|
|
|
115
127
|
// find the inverse
|
|
116
128
|
let x = 1;
|
|
117
129
|
let y = 0;
|
|
118
|
-
for (let i = s.length - 2; i >= 0;
|
|
130
|
+
for (let i = s.length - 2; i >= 0; i -= 1) {
|
|
119
131
|
[x, y] = [y, x - y * Math.floor(s[i]!.a / s[i]!.b)];
|
|
120
132
|
}
|
|
121
|
-
return (y % m + m) % m;
|
|
133
|
+
return ((y % m) + m) % m;
|
|
122
134
|
}
|
|
123
135
|
|
|
124
136
|
export function calculatePublicKeyLength() {
|
|
125
137
|
return 4 + 4 + 2048 / 8 + 2048 / 8 + 4;
|
|
126
138
|
}
|
|
127
139
|
|
|
128
|
-
export function calculatePublicKey(
|
|
129
|
-
privateKey: Uint8Array
|
|
130
|
-
): Uint8Array;
|
|
140
|
+
export function calculatePublicKey(privateKey: Uint8Array): Uint8Array;
|
|
131
141
|
export function calculatePublicKey(
|
|
132
142
|
privateKey: Uint8Array,
|
|
133
|
-
output: Uint8Array
|
|
143
|
+
output: Uint8Array
|
|
134
144
|
): number;
|
|
135
145
|
export function calculatePublicKey(
|
|
136
146
|
privateKey: Uint8Array,
|
|
137
|
-
output?: Uint8Array
|
|
147
|
+
output?: Uint8Array
|
|
138
148
|
): Uint8Array | number {
|
|
139
149
|
// Android has its own public key generation algorithm
|
|
140
150
|
// See https://android.googlesource.com/platform/system/core.git/+/91784040db2b9273687f88d8b95f729d4a61ecc2/libcrypto_utils/android_pubkey.cpp#111
|
|
@@ -156,20 +166,24 @@ export function calculatePublicKey(
|
|
|
156
166
|
// extract `n` from private key
|
|
157
167
|
const [n] = parsePrivateKey(privateKey);
|
|
158
168
|
|
|
159
|
-
let outputType:
|
|
169
|
+
let outputType: "Uint8Array" | "number";
|
|
160
170
|
const outputLength = calculatePublicKeyLength();
|
|
161
171
|
if (!output) {
|
|
162
172
|
output = new Uint8Array(outputLength);
|
|
163
|
-
outputType =
|
|
173
|
+
outputType = "Uint8Array";
|
|
164
174
|
} else {
|
|
165
175
|
if (output.byteLength < outputLength) {
|
|
166
|
-
throw new Error(
|
|
176
|
+
throw new Error("output buffer is too small");
|
|
167
177
|
}
|
|
168
178
|
|
|
169
|
-
outputType =
|
|
179
|
+
outputType = "number";
|
|
170
180
|
}
|
|
171
181
|
|
|
172
|
-
const outputView = new DataView(
|
|
182
|
+
const outputView = new DataView(
|
|
183
|
+
output.buffer,
|
|
184
|
+
output.byteOffset,
|
|
185
|
+
output.byteLength
|
|
186
|
+
);
|
|
173
187
|
let outputOffset = 0;
|
|
174
188
|
|
|
175
189
|
// modulusLengthInWords
|
|
@@ -179,7 +193,10 @@ export function calculatePublicKey(
|
|
|
179
193
|
// Calculate `n0inv`
|
|
180
194
|
// Don't know why need to multiple -1
|
|
181
195
|
// Didn't exist in Android codebase
|
|
182
|
-
const n0inv = modInverse(
|
|
196
|
+
const n0inv = modInverse(
|
|
197
|
+
Number(BigInt.asUintN(32, n) * BigInt(-1)),
|
|
198
|
+
2 ** 32
|
|
199
|
+
);
|
|
183
200
|
outputView.setUint32(outputOffset, n0inv, true);
|
|
184
201
|
outputOffset += 4;
|
|
185
202
|
|
|
@@ -188,14 +205,14 @@ export function calculatePublicKey(
|
|
|
188
205
|
outputOffset += 256;
|
|
189
206
|
|
|
190
207
|
// Calculate rr = (2^(rsa_size)) ^ 2 mod n
|
|
191
|
-
|
|
208
|
+
const rr = BigInt(2) ** BigInt(4096) % n;
|
|
192
209
|
outputOffset += setBigUint(outputView, outputOffset, rr, true);
|
|
193
210
|
|
|
194
211
|
// exponent
|
|
195
212
|
outputView.setUint32(outputOffset, 65537, true);
|
|
196
213
|
outputOffset += 4;
|
|
197
214
|
|
|
198
|
-
if (outputType ===
|
|
215
|
+
if (outputType === "Uint8Array") {
|
|
199
216
|
return output;
|
|
200
217
|
} else {
|
|
201
218
|
return outputLength;
|
|
@@ -209,7 +226,11 @@ export function calculatePublicKey(
|
|
|
209
226
|
*
|
|
210
227
|
* See https://en.wikipedia.org/wiki/Modular_exponentiation#Implementation_in_Lua
|
|
211
228
|
*/
|
|
212
|
-
export function powMod(
|
|
229
|
+
export function powMod(
|
|
230
|
+
base: bigint,
|
|
231
|
+
exponent: bigint,
|
|
232
|
+
modulus: bigint
|
|
233
|
+
): bigint {
|
|
213
234
|
if (modulus === BigInt1) {
|
|
214
235
|
return BigInt0;
|
|
215
236
|
}
|
|
@@ -219,7 +240,7 @@ export function powMod(base: bigint, exponent: bigint, modulus: bigint): bigint
|
|
|
219
240
|
|
|
220
241
|
while (exponent > BigInt0) {
|
|
221
242
|
if (BigInt.asUintN(1, exponent) === BigInt1) {
|
|
222
|
-
r = r * base % modulus;
|
|
243
|
+
r = (r * base) % modulus;
|
|
223
244
|
}
|
|
224
245
|
|
|
225
246
|
exponent >>= BigInt1;
|
|
@@ -238,12 +259,22 @@ export const ASN1_OID = 0x06;
|
|
|
238
259
|
|
|
239
260
|
// PKCS#1 SHA-1 hash digest info
|
|
240
261
|
export const SHA1_DIGEST_INFO = new Uint8Array([
|
|
241
|
-
ASN1_SEQUENCE,
|
|
242
|
-
|
|
262
|
+
ASN1_SEQUENCE,
|
|
263
|
+
0x0d + SHA1_DIGEST_LENGTH,
|
|
264
|
+
ASN1_SEQUENCE,
|
|
265
|
+
0x09,
|
|
243
266
|
// SHA-1 (1 3 14 3 2 26)
|
|
244
|
-
ASN1_OID,
|
|
245
|
-
|
|
246
|
-
|
|
267
|
+
ASN1_OID,
|
|
268
|
+
0x05,
|
|
269
|
+
1 * 40 + 3,
|
|
270
|
+
14,
|
|
271
|
+
3,
|
|
272
|
+
2,
|
|
273
|
+
26,
|
|
274
|
+
ASN1_NULL,
|
|
275
|
+
0x00,
|
|
276
|
+
ASN1_OCTET_STRING,
|
|
277
|
+
SHA1_DIGEST_LENGTH,
|
|
247
278
|
]);
|
|
248
279
|
|
|
249
280
|
// SubtleCrypto.sign() will hash the given data and sign the hash
|
|
@@ -265,7 +296,8 @@ export function sign(privateKey: Uint8Array, data: Uint8Array): Uint8Array {
|
|
|
265
296
|
padded[index] = 1;
|
|
266
297
|
index += 1;
|
|
267
298
|
|
|
268
|
-
const fillLength =
|
|
299
|
+
const fillLength =
|
|
300
|
+
padded.length - SHA1_DIGEST_INFO.length - data.length - 1;
|
|
269
301
|
while (index < fillLength) {
|
|
270
302
|
padded[index] = 0xff;
|
|
271
303
|
index += 1;
|
|
@@ -282,11 +314,7 @@ export function sign(privateKey: Uint8Array, data: Uint8Array): Uint8Array {
|
|
|
282
314
|
// Encryption
|
|
283
315
|
// signature = padded ** d % n
|
|
284
316
|
const view = new DataView(padded.buffer);
|
|
285
|
-
const signature = powMod(
|
|
286
|
-
getBigUint(view, 0, view.byteLength),
|
|
287
|
-
d,
|
|
288
|
-
n
|
|
289
|
-
);
|
|
317
|
+
const signature = powMod(getBigUint(view, 0, view.byteLength), d, n);
|
|
290
318
|
|
|
291
319
|
// `padded` is not used anymore,
|
|
292
320
|
// re-use the buffer to store the result
|
package/src/features.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
// The order follows
|
|
2
2
|
// https://android.googlesource.com/platform/packages/modules/adb/+/79010dc6d5ca7490c493df800d4421730f5466ca/transport.cpp#1252
|
|
3
|
-
export enum
|
|
4
|
-
ShellV2 =
|
|
5
|
-
Cmd =
|
|
6
|
-
StatV2 =
|
|
7
|
-
ListV2 =
|
|
8
|
-
FixedPushMkdir =
|
|
3
|
+
export enum AdbFeature {
|
|
4
|
+
ShellV2 = "shell_v2",
|
|
5
|
+
Cmd = "cmd",
|
|
6
|
+
StatV2 = "stat_v2",
|
|
7
|
+
ListV2 = "ls_v2",
|
|
8
|
+
FixedPushMkdir = "fixed_push_mkdir",
|
|
9
|
+
Abb = "abb",
|
|
10
|
+
AbbExec = "abb_exec",
|
|
11
|
+
SendReceiveV2 = "sendrecv_v2",
|
|
9
12
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
8
|
-
export * from
|
|
9
|
-
export * from
|
|
10
|
-
export * from './utils/index.js';
|
|
1
|
+
export * from "./adb.js";
|
|
2
|
+
export * from "./auth.js";
|
|
3
|
+
export * from "./backend.js";
|
|
4
|
+
export * from "./commands/index.js";
|
|
5
|
+
export * from "./crypto.js";
|
|
6
|
+
export * from "./features.js";
|
|
7
|
+
export * from "./packet.js";
|
|
8
|
+
export * from "./socket/index.js";
|
|
9
|
+
export * from "./utils/index.js";
|
package/src/packet.ts
CHANGED
|
@@ -1,34 +1,32 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Struct from
|
|
1
|
+
import { ConsumableTransformStream } from "@yume-chan/stream-extra";
|
|
2
|
+
import Struct from "@yume-chan/struct";
|
|
3
3
|
|
|
4
4
|
export enum AdbCommand {
|
|
5
|
-
Auth = 0x48545541,
|
|
6
|
-
Close = 0x45534c43,
|
|
5
|
+
Auth = 0x48545541, // 'AUTH'
|
|
6
|
+
Close = 0x45534c43, // 'CLSE'
|
|
7
7
|
Connect = 0x4e584e43, // 'CNXN'
|
|
8
|
-
OK = 0x59414b4f,
|
|
9
|
-
Open = 0x4e45504f,
|
|
10
|
-
Write = 0x45545257,
|
|
8
|
+
OK = 0x59414b4f, // 'OKAY'
|
|
9
|
+
Open = 0x4e45504f, // 'OPEN'
|
|
10
|
+
Write = 0x45545257, // 'WRTE'
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export const AdbPacketHeader =
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
.int32('magic');
|
|
13
|
+
export const AdbPacketHeader = new Struct({ littleEndian: true })
|
|
14
|
+
.uint32("command")
|
|
15
|
+
.uint32("arg0")
|
|
16
|
+
.uint32("arg1")
|
|
17
|
+
.uint32("payloadLength")
|
|
18
|
+
.uint32("checksum")
|
|
19
|
+
.int32("magic");
|
|
21
20
|
|
|
22
|
-
export type AdbPacketHeader = typeof AdbPacketHeader[
|
|
21
|
+
export type AdbPacketHeader = (typeof AdbPacketHeader)["TDeserializeResult"];
|
|
23
22
|
|
|
24
|
-
type AdbPacketHeaderInit = typeof AdbPacketHeader[
|
|
23
|
+
type AdbPacketHeaderInit = (typeof AdbPacketHeader)["TInit"];
|
|
25
24
|
|
|
26
|
-
export const AdbPacket =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.uint8Array('payload', { lengthField: 'payloadLength' });
|
|
25
|
+
export const AdbPacket = new Struct({ littleEndian: true })
|
|
26
|
+
.fields(AdbPacketHeader)
|
|
27
|
+
.uint8Array("payload", { lengthField: "payloadLength" });
|
|
30
28
|
|
|
31
|
-
export type AdbPacket = typeof AdbPacket[
|
|
29
|
+
export type AdbPacket = (typeof AdbPacket)["TDeserializeResult"];
|
|
32
30
|
|
|
33
31
|
/**
|
|
34
32
|
* `AdbPacketData` contains all the useful fields of `AdbPacket`.
|
|
@@ -40,39 +38,36 @@ export type AdbPacket = typeof AdbPacket['TDeserializeResult'];
|
|
|
40
38
|
* however, `AdbPacketDispatcher` will transform `AdbPacketData` to `AdbPacketInit` for you,
|
|
41
39
|
* so `AdbSocket#writable#write` only needs `AdbPacketData`.
|
|
42
40
|
*/
|
|
43
|
-
export type AdbPacketData = Omit<
|
|
41
|
+
export type AdbPacketData = Omit<
|
|
42
|
+
(typeof AdbPacket)["TInit"],
|
|
43
|
+
"checksum" | "magic"
|
|
44
|
+
>;
|
|
44
45
|
|
|
45
|
-
|
|
46
|
-
export type AdbPacketInit = Omit<typeof AdbPacket['TInit'], 'magic'>;
|
|
46
|
+
export type AdbPacketInit = (typeof AdbPacket)["TInit"];
|
|
47
47
|
|
|
48
|
-
export function calculateChecksum(payload: Uint8Array): number
|
|
49
|
-
|
|
50
|
-
export function calculateChecksum(payload: Uint8Array | AdbPacketData): number | AdbPacketInit {
|
|
51
|
-
if (payload instanceof Uint8Array) {
|
|
52
|
-
return payload.reduce((result, item) => result + item, 0);
|
|
53
|
-
} else {
|
|
54
|
-
(payload as AdbPacketInit).checksum = calculateChecksum(payload.payload);
|
|
55
|
-
return payload as AdbPacketInit;
|
|
56
|
-
}
|
|
48
|
+
export function calculateChecksum(payload: Uint8Array): number {
|
|
49
|
+
return payload.reduce((result, item) => result + item, 0);
|
|
57
50
|
}
|
|
58
51
|
|
|
59
|
-
export class AdbPacketSerializeStream extends
|
|
52
|
+
export class AdbPacketSerializeStream extends ConsumableTransformStream<
|
|
53
|
+
AdbPacketInit,
|
|
54
|
+
Uint8Array
|
|
55
|
+
> {
|
|
60
56
|
public constructor() {
|
|
57
|
+
const headerBuffer = new Uint8Array(AdbPacketHeader.size);
|
|
61
58
|
super({
|
|
62
|
-
transform: async (
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
(init as unknown as AdbPacketHeaderInit).payloadLength = init.payload.byteLength;
|
|
59
|
+
transform: async (chunk, controller) => {
|
|
60
|
+
const init = chunk as AdbPacketInit & AdbPacketHeaderInit;
|
|
61
|
+
init.payloadLength = init.payload.byteLength;
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
init as unknown as AdbPacketHeaderInit
|
|
70
|
-
)
|
|
71
|
-
);
|
|
63
|
+
AdbPacketHeader.serialize(init, headerBuffer);
|
|
64
|
+
await controller.enqueue(headerBuffer);
|
|
72
65
|
|
|
73
66
|
if (init.payload.byteLength) {
|
|
74
|
-
//
|
|
75
|
-
|
|
67
|
+
// USB protocol preserves packet boundaries,
|
|
68
|
+
// so we must write payload separately as native ADB does,
|
|
69
|
+
// otherwise the read operation on device will fail.
|
|
70
|
+
await controller.enqueue(init.payload);
|
|
76
71
|
}
|
|
77
72
|
},
|
|
78
73
|
});
|