first commit

This commit is contained in:
2026-09-08 20:28:54 +08:00
commit 2ada8d3d5a
37380 changed files with 4886169 additions and 0 deletions
+112
View File
@@ -0,0 +1,112 @@
var Packet;
Packet = (function() {
Packet.A_SYNC = 0x434e5953;
Packet.A_CNXN = 0x4e584e43;
Packet.A_OPEN = 0x4e45504f;
Packet.A_OKAY = 0x59414b4f;
Packet.A_CLSE = 0x45534c43;
Packet.A_WRTE = 0x45545257;
Packet.A_AUTH = 0x48545541;
Packet.checksum = function(data) {
var char, i, len, sum;
sum = 0;
if (data) {
for (i = 0, len = data.length; i < len; i++) {
char = data[i];
sum += char;
}
}
return sum;
};
Packet.magic = function(command) {
return (command ^ 0xffffffff) >>> 0;
};
Packet.assemble = function(command, arg0, arg1, data) {
var chunk;
if (data) {
chunk = new Buffer(24 + data.length);
chunk.writeUInt32LE(command, 0);
chunk.writeUInt32LE(arg0, 4);
chunk.writeUInt32LE(arg1, 8);
chunk.writeUInt32LE(data.length, 12);
chunk.writeUInt32LE(Packet.checksum(data), 16);
chunk.writeUInt32LE(Packet.magic(command), 20);
data.copy(chunk, 24);
return chunk;
} else {
chunk = new Buffer(24);
chunk.writeUInt32LE(command, 0);
chunk.writeUInt32LE(arg0, 4);
chunk.writeUInt32LE(arg1, 8);
chunk.writeUInt32LE(0, 12);
chunk.writeUInt32LE(0, 16);
chunk.writeUInt32LE(Packet.magic(command), 20);
return chunk;
}
};
Packet.swap32 = function(n) {
var buffer;
buffer = new Buffer(4);
buffer.writeUInt32LE(n, 0);
return buffer.readUInt32BE(0);
};
function Packet(command1, arg01, arg11, length, check, magic, data1) {
this.command = command1;
this.arg0 = arg01;
this.arg1 = arg11;
this.length = length;
this.check = check;
this.magic = magic;
this.data = data1;
}
Packet.prototype.verifyChecksum = function() {
return this.check === Packet.checksum(this.data);
};
Packet.prototype.verifyMagic = function() {
return this.magic === Packet.magic(this.command);
};
Packet.prototype.toString = function() {
var type;
type = (function() {
switch (this.command) {
case Packet.A_SYNC:
return "SYNC";
case Packet.A_CNXN:
return "CNXN";
case Packet.A_OPEN:
return "OPEN";
case Packet.A_OKAY:
return "OKAY";
case Packet.A_CLSE:
return "CLSE";
case Packet.A_WRTE:
return "WRTE";
case Packet.A_AUTH:
return "AUTH";
default:
throw new Error("Unknown command {@command}");
}
}).call(this);
return type + " arg0=" + this.arg0 + " arg1=" + this.arg1 + " length=" + this.length;
};
return Packet;
})();
module.exports = Packet;
+121
View File
@@ -0,0 +1,121 @@
var EventEmitter, Packet, PacketReader,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
EventEmitter = require('events').EventEmitter;
Packet = require('./packet');
PacketReader = (function(superClass) {
extend(PacketReader, superClass);
function PacketReader(stream) {
this.stream = stream;
PacketReader.__super__.constructor.call(this);
this.inBody = false;
this.buffer = null;
this.packet = null;
this.stream.on('readable', this._tryRead.bind(this));
this.stream.on('error', (function(_this) {
return function(err) {
return _this.emit('error', err);
};
})(this));
this.stream.on('end', (function(_this) {
return function() {
return _this.emit('end');
};
})(this));
setImmediate(this._tryRead.bind(this));
}
PacketReader.prototype._tryRead = function() {
var header;
while (this._appendChunk()) {
while (this.buffer) {
if (this.inBody) {
if (!(this.buffer.length >= this.packet.length)) {
break;
}
this.packet.data = this._consume(this.packet.length);
if (!this.packet.verifyChecksum()) {
this.emit('error', new PacketReader.ChecksumError(this.packet));
return;
}
this.emit('packet', this.packet);
this.inBody = false;
} else {
if (!(this.buffer.length >= 24)) {
break;
}
header = this._consume(24);
this.packet = new Packet(header.readUInt32LE(0), header.readUInt32LE(4), header.readUInt32LE(8), header.readUInt32LE(12), header.readUInt32LE(16), header.readUInt32LE(20), new Buffer(0));
if (!this.packet.verifyMagic()) {
this.emit('error', new PacketReader.MagicError(this.packet));
return;
}
if (this.packet.length === 0) {
this.emit('packet', this.packet);
} else {
this.inBody = true;
}
}
}
}
};
PacketReader.prototype._appendChunk = function() {
var chunk;
if (chunk = this.stream.read()) {
if (this.buffer) {
return this.buffer = Buffer.concat([this.buffer, chunk], this.buffer.length + chunk.length);
} else {
return this.buffer = chunk;
}
} else {
return null;
}
};
PacketReader.prototype._consume = function(length) {
var chunk;
chunk = this.buffer.slice(0, length);
this.buffer = length === this.buffer.length ? null : this.buffer.slice(length);
return chunk;
};
return PacketReader;
})(EventEmitter);
PacketReader.ChecksumError = (function(superClass) {
extend(ChecksumError, superClass);
function ChecksumError(packet) {
this.packet = packet;
Error.call(this);
this.name = 'ChecksumError';
this.message = "Checksum mismatch";
Error.captureStackTrace(this, PacketReader.ChecksumError);
}
return ChecksumError;
})(Error);
PacketReader.MagicError = (function(superClass) {
extend(MagicError, superClass);
function MagicError(packet) {
this.packet = packet;
Error.call(this);
this.name = 'MagicError';
this.message = "Magic value mismatch";
Error.captureStackTrace(this, PacketReader.MagicError);
}
return MagicError;
})(Error);
module.exports = PacketReader;
+21
View File
@@ -0,0 +1,21 @@
var RollingCounter;
RollingCounter = (function() {
function RollingCounter(max, min) {
this.max = max;
this.min = min != null ? min : 1;
this.now = this.min;
}
RollingCounter.prototype.next = function() {
if (!(this.now < this.max)) {
this.now = this.min;
}
return ++this.now;
};
return RollingCounter;
})();
module.exports = RollingCounter;
+79
View File
@@ -0,0 +1,79 @@
var EventEmitter, Net, Server, Socket,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
Net = require('net');
EventEmitter = require('events').EventEmitter;
Socket = require('./socket');
Server = (function(superClass) {
extend(Server, superClass);
function Server(client, serial, options) {
this.client = client;
this.serial = serial;
this.options = options;
this.connections = [];
this.server = Net.createServer({
allowHalfOpen: true
});
this.server.on('error', (function(_this) {
return function(err) {
return _this.emit('error', err);
};
})(this));
this.server.on('listening', (function(_this) {
return function() {
return _this.emit('listening');
};
})(this));
this.server.on('close', (function(_this) {
return function() {
return _this.emit('close');
};
})(this));
this.server.on('connection', (function(_this) {
return function(conn) {
var socket;
socket = new Socket(_this.client, _this.serial, conn, _this.options);
_this.connections.push(socket);
socket.on('error', function(err) {
return _this.emit('error', err);
});
socket.once('end', function() {
return _this.connections = _this.connections.filter(function(val) {
return val !== socket;
});
});
return _this.emit('connection', socket);
};
})(this));
}
Server.prototype.listen = function() {
this.server.listen.apply(this.server, arguments);
return this;
};
Server.prototype.close = function() {
this.server.close();
return this;
};
Server.prototype.end = function() {
var conn, i, len, ref;
ref = this.connections;
for (i = 0, len = ref.length; i < len; i++) {
conn = ref[i];
conn.end();
}
return this;
};
return Server;
})(EventEmitter);
module.exports = Server;
+203
View File
@@ -0,0 +1,203 @@
var EventEmitter, Packet, Parser, Promise, Protocol, Service, debug,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
EventEmitter = require('events').EventEmitter;
Promise = require('bluebird');
debug = require('debug')('adb:tcpusb:service');
Parser = require('../parser');
Protocol = require('../protocol');
Packet = require('./packet');
Service = (function(superClass) {
extend(Service, superClass);
function Service(client, serial, localId1, remoteId, socket) {
this.client = client;
this.serial = serial;
this.localId = localId1;
this.remoteId = remoteId;
this.socket = socket;
Service.__super__.constructor.call(this);
this.opened = false;
this.ended = false;
this.transport = null;
this.needAck = false;
}
Service.prototype.end = function() {
var err, localId;
if (this.transport) {
this.transport.end();
}
if (this.ended) {
return this;
}
debug('O:A_CLSE');
localId = this.opened ? this.localId : 0;
try {
this.socket.write(Packet.assemble(Packet.A_CLSE, localId, this.remoteId, null));
} catch (_error) {
err = _error;
}
this.transport = null;
this.ended = true;
this.emit('end');
return this;
};
Service.prototype.handle = function(packet) {
return Promise["try"]((function(_this) {
return function() {
switch (packet.command) {
case Packet.A_OPEN:
return _this._handleOpenPacket(packet);
case Packet.A_OKAY:
return _this._handleOkayPacket(packet);
case Packet.A_WRTE:
return _this._handleWritePacket(packet);
case Packet.A_CLSE:
return _this._handleClosePacket(packet);
default:
throw new Error("Unexpected packet " + packet.command);
}
};
})(this))["catch"]((function(_this) {
return function(err) {
_this.emit('error', err);
return _this.end();
};
})(this));
};
Service.prototype._handleOpenPacket = function(packet) {
debug('I:A_OPEN', packet);
return this.client.transport(this.serial).then((function(_this) {
return function(transport) {
_this.transport = transport;
if (_this.ended) {
throw new LateTransportError();
}
_this.transport.write(Protocol.encodeData(packet.data.slice(0, -1)));
return _this.transport.parser.readAscii(4).then(function(reply) {
switch (reply) {
case Protocol.OKAY:
debug('O:A_OKAY');
_this.socket.write(Packet.assemble(Packet.A_OKAY, _this.localId, _this.remoteId, null));
return _this.opened = true;
case Protocol.FAIL:
return _this.transport.parser.readError();
default:
return _this.transport.parser.unexpected(reply, 'OKAY or FAIL');
}
});
};
})(this)).then((function(_this) {
return function() {
return new Promise(function(resolve, reject) {
_this.transport.socket.on('readable', function() {
return _this._tryPush();
}).on('end', resolve).on('error', reject);
return _this._tryPush();
});
};
})(this))["finally"]((function(_this) {
return function() {
return _this.end();
};
})(this));
};
Service.prototype._handleOkayPacket = function(packet) {
debug('I:A_OKAY', packet);
if (this.ended) {
return;
}
if (!this.transport) {
throw new Service.PrematurePacketError(packet);
}
this.needAck = false;
return this._tryPush();
};
Service.prototype._handleWritePacket = function(packet) {
debug('I:A_WRTE', packet);
if (this.ended) {
return;
}
if (!this.transport) {
throw new Service.PrematurePacketError(packet);
}
if (packet.data) {
this.transport.write(packet.data);
}
debug('O:A_OKAY');
return this.socket.write(Packet.assemble(Packet.A_OKAY, this.localId, this.remoteId, null));
};
Service.prototype._handleClosePacket = function(packet) {
debug('I:A_CLSE', packet);
if (this.ended) {
return;
}
if (!this.transport) {
throw new Service.PrematurePacketError(packet);
}
return this.end();
};
Service.prototype._tryPush = function() {
var chunk;
if (this.needAck || this.ended) {
return;
}
if (chunk = this._readChunk(this.transport.socket)) {
debug('O:A_WRTE');
this.socket.write(Packet.assemble(Packet.A_WRTE, this.localId, this.remoteId, chunk));
return this.needAck = true;
}
};
Service.prototype._readChunk = function(stream) {
return stream.read(this.socket.maxPayload) || stream.read();
};
return Service;
})(EventEmitter);
Service.PrematurePacketError = (function(superClass) {
extend(PrematurePacketError, superClass);
function PrematurePacketError(packet1) {
this.packet = packet1;
Error.call(this);
this.name = 'PrematurePacketError';
this.message = "Premature packet";
Error.captureStackTrace(this, Service.PrematurePacketError);
}
return PrematurePacketError;
})(Error);
Service.LateTransportError = (function(superClass) {
extend(LateTransportError, superClass);
function LateTransportError() {
Error.call(this);
this.name = 'LateTransportError';
this.message = "Late transport";
Error.captureStackTrace(this, Service.LateTransportError);
}
return LateTransportError;
})(Error);
module.exports = Service;
+48
View File
@@ -0,0 +1,48 @@
var ServiceMap;
ServiceMap = (function() {
function ServiceMap() {
this.remotes = Object.create(null);
this.count = 0;
}
ServiceMap.prototype.end = function() {
var ref, remote, remoteId;
ref = this.remotes;
for (remoteId in ref) {
remote = ref[remoteId];
remote.end();
}
this.remotes = Object.create(null);
this.count = 0;
};
ServiceMap.prototype.insert = function(remoteId, socket) {
if (this.remotes[remoteId]) {
throw new Error("Remote ID " + remoteId + " is already being used");
} else {
this.count += 1;
return this.remotes[remoteId] = socket;
}
};
ServiceMap.prototype.get = function(remoteId) {
return this.remotes[remoteId] || null;
};
ServiceMap.prototype.remove = function(remoteId) {
var remote;
if (remote = this.remotes[remoteId]) {
delete this.remotes[remoteId];
this.count -= 1;
return remote;
} else {
return null;
}
};
return ServiceMap;
})();
module.exports = ServiceMap;
+314
View File
@@ -0,0 +1,314 @@
var Auth, EventEmitter, Forge, Packet, PacketReader, Parser, Promise, Protocol, RollingCounter, Service, ServiceMap, Socket, crypto, debug,
extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
hasProp = {}.hasOwnProperty;
crypto = require('crypto');
EventEmitter = require('events').EventEmitter;
Promise = require('bluebird');
Forge = require('node-forge');
debug = require('debug')('adb:tcpusb:socket');
Parser = require('../parser');
Protocol = require('../protocol');
Auth = require('../auth');
Packet = require('./packet');
PacketReader = require('./packetreader');
Service = require('./service');
ServiceMap = require('./servicemap');
RollingCounter = require('./rollingcounter');
Socket = (function(superClass) {
var AUTH_RSAPUBLICKEY, AUTH_SIGNATURE, AUTH_TOKEN, TOKEN_LENGTH, UINT16_MAX, UINT32_MAX;
extend(Socket, superClass);
UINT32_MAX = 0xFFFFFFFF;
UINT16_MAX = 0xFFFF;
AUTH_TOKEN = 1;
AUTH_SIGNATURE = 2;
AUTH_RSAPUBLICKEY = 3;
TOKEN_LENGTH = 20;
function Socket(client, serial, socket, options) {
var base;
this.client = client;
this.serial = serial;
this.socket = socket;
this.options = options != null ? options : {};
(base = this.options).auth || (base.auth = Promise.resolve(true));
this.ended = false;
this.socket.setNoDelay(true);
this.reader = new PacketReader(this.socket).on('packet', this._handle.bind(this)).on('error', (function(_this) {
return function(err) {
debug("PacketReader error: " + err.message);
return _this.end();
};
})(this)).on('end', this.end.bind(this));
this.version = 1;
this.maxPayload = 4096;
this.authorized = false;
this.syncToken = new RollingCounter(UINT32_MAX);
this.remoteId = new RollingCounter(UINT32_MAX);
this.services = new ServiceMap;
this.remoteAddress = this.socket.remoteAddress;
this.token = null;
this.signature = null;
}
Socket.prototype.end = function() {
if (this.ended) {
return this;
}
this.services.end();
this.socket.end();
this.ended = true;
this.emit('end');
return this;
};
Socket.prototype._error = function(err) {
this.emit('error', err);
return this.end();
};
Socket.prototype._handle = function(packet) {
if (this.ended) {
return;
}
this.emit('userActivity', packet);
return Promise["try"]((function(_this) {
return function() {
switch (packet.command) {
case Packet.A_SYNC:
return _this._handleSyncPacket(packet);
case Packet.A_CNXN:
return _this._handleConnectionPacket(packet);
case Packet.A_OPEN:
return _this._handleOpenPacket(packet);
case Packet.A_OKAY:
case Packet.A_WRTE:
case Packet.A_CLSE:
return _this._forwardServicePacket(packet);
case Packet.A_AUTH:
return _this._handleAuthPacket(packet);
default:
throw new Error("Unknown command " + packet.command);
}
};
})(this))["catch"](Socket.AuthError, (function(_this) {
return function() {
return _this.end();
};
})(this))["catch"](Socket.UnauthorizedError, (function(_this) {
return function() {
return _this.end();
};
})(this))["catch"]((function(_this) {
return function(err) {
return _this._error(err);
};
})(this));
};
Socket.prototype._handleSyncPacket = function(packet) {
debug('I:A_SYNC');
debug('O:A_SYNC');
return this.write(Packet.assemble(Packet.A_SYNC, 1, this.syncToken.next(), null));
};
Socket.prototype._handleConnectionPacket = function(packet) {
var version;
debug('I:A_CNXN', packet);
version = Packet.swap32(packet.arg0);
this.maxPayload = Math.min(UINT16_MAX, packet.arg1);
return this._createToken().then((function(_this) {
return function(token) {
_this.token = token;
debug("Created challenge '" + (_this.token.toString('base64')) + "'");
debug('O:A_AUTH');
return _this.write(Packet.assemble(Packet.A_AUTH, AUTH_TOKEN, 0, _this.token));
};
})(this));
};
Socket.prototype._handleAuthPacket = function(packet) {
debug('I:A_AUTH', packet);
switch (packet.arg0) {
case AUTH_SIGNATURE:
debug("Received signature '" + (packet.data.toString('base64')) + "'");
if (!this.signature) {
this.signature = packet.data;
}
debug('O:A_AUTH');
return this.write(Packet.assemble(Packet.A_AUTH, AUTH_TOKEN, 0, this.token));
case AUTH_RSAPUBLICKEY:
if (!this.signature) {
throw new Socket.AuthError("Public key sent before signature");
}
if (!(packet.data && packet.data.length >= 2)) {
throw new Socket.AuthError("Empty RSA public key");
}
debug("Received RSA public key '" + (packet.data.toString('base64')) + "'");
return Auth.parsePublicKey(this._skipNull(packet.data)).then((function(_this) {
return function(key) {
var digest, sig;
digest = _this.token.toString('binary');
sig = _this.signature.toString('binary');
if (!key.verify(digest, sig)) {
debug("Signature mismatch");
throw new Socket.AuthError("Signature mismatch");
}
debug("Signature verified");
return key;
};
})(this)).then((function(_this) {
return function(key) {
return _this.options.auth(key)["catch"](function(err) {
debug("Connection rejected by user-defined auth handler");
throw new Socket.AuthError("Rejected by user-defined handler");
});
};
})(this)).then((function(_this) {
return function() {
return _this._deviceId();
};
})(this)).then((function(_this) {
return function(id) {
_this.authorized = true;
debug('O:A_CNXN');
return _this.write(Packet.assemble(Packet.A_CNXN, Packet.swap32(_this.version), _this.maxPayload, id));
};
})(this));
default:
throw new Error("Unknown authentication method " + packet.arg0);
}
};
Socket.prototype._handleOpenPacket = function(packet) {
var localId, name, remoteId, service;
if (!this.authorized) {
throw new Socket.UnauthorizedError();
}
remoteId = packet.arg0;
localId = this.remoteId.next();
if (!(packet.data && packet.data.length >= 2)) {
throw new Error("Empty service name");
}
name = this._skipNull(packet.data);
debug("Calling " + name);
service = new Service(this.client, this.serial, localId, remoteId, this);
return new Promise((function(_this) {
return function(resolve, reject) {
service.on('error', reject);
service.on('end', resolve);
_this.services.insert(localId, service);
debug("Handling " + _this.services.count + " services simultaneously");
return service.handle(packet);
};
})(this))["catch"](function(err) {
return true;
})["finally"]((function(_this) {
return function() {
_this.services.remove(localId);
debug("Handling " + _this.services.count + " services simultaneously");
return service.end();
};
})(this));
};
Socket.prototype._forwardServicePacket = function(packet) {
var localId, remoteId, service;
if (!this.authorized) {
throw new Socket.UnauthorizedError();
}
remoteId = packet.arg0;
localId = packet.arg1;
if (service = this.services.get(localId)) {
return service.handle(packet);
} else {
return debug("Received a packet to a service that may have been closed already");
}
};
Socket.prototype.write = function(chunk) {
if (this.ended) {
return;
}
return this.socket.write(chunk);
};
Socket.prototype._createToken = function() {
return Promise.promisify(crypto.randomBytes)(TOKEN_LENGTH);
};
Socket.prototype._skipNull = function(data) {
return data.slice(0, -1);
};
Socket.prototype._deviceId = function() {
debug("Loading device properties to form a standard device ID");
return this.client.getProperties(this.serial).then(function(properties) {
var id, prop;
id = ((function() {
var i, len, ref, results;
ref = ['ro.product.name', 'ro.product.model', 'ro.product.device'];
results = [];
for (i = 0, len = ref.length; i < len; i++) {
prop = ref[i];
results.push(prop + "=" + properties[prop] + ";");
}
return results;
})()).join('');
return new Buffer("device::" + id + "\0");
});
};
return Socket;
})(EventEmitter);
Socket.AuthError = (function(superClass) {
extend(AuthError, superClass);
function AuthError(message) {
this.message = message;
Error.call(this);
this.name = 'AuthError';
Error.captureStackTrace(this, Socket.AuthError);
}
return AuthError;
})(Error);
Socket.UnauthorizedError = (function(superClass) {
extend(UnauthorizedError, superClass);
function UnauthorizedError() {
Error.call(this);
this.name = 'UnauthorizedError';
this.message = "Unauthorized access";
Error.captureStackTrace(this, Socket.UnauthorizedError);
}
return UnauthorizedError;
})(Error);
module.exports = Socket;