Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f6c446b1 authored by Frank PREEL's avatar Frank PREEL
Browse files

Replace adb library

parent 8b88decc
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
MIT License

Copyright (c) 2020 Sphantix Hang

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+2678 −0

File added.

Preview size limit exceeded, changes collapsed.

+0 −56
Original line number Diff line number Diff line
export class Helper {
    static paddit(text, width, padding) {
        const padlen = width - text.length;
        let padded = '';
        for (let i = 0; i < padlen; i++) {
            padded += padding;
        }
        return padded + text;
    }

    static toHex8(num) {
        return this.paddit(num.toString(16), 2, '0');
    }

    static toHex16(num) {
        return this.paddit(num.toString(16), 4, '0');
    }

    static toHex32(num) {
        return this.paddit(num.toString(16), 8, '0');
    }

    static hexdump(view, prefix = '') {
        const decoder = new TextDecoder();
        let global = '';
        for (let i = 0; i < view.byteLength; i += 16) {
            const max = (view.byteLength - i) > 16 ? 16 : (view.byteLength - i);
            let row = prefix + this.toHex16(i) + ' ';
            let j;
            for (j = 0; j < max; j++) {
                row += ' ' + this.toHex8(view.getUint8(i + j));
            }
            for (; j < 16; j++) {
                row += '   ';
            }
            row += ' | ' + decoder.decode(new DataView(view.buffer, i, max));
            global += row;
        }
        return global;
    }

    static encodeCmd(cmd) {
        const encoder = new TextEncoder();
        const buffer = encoder.encode(cmd).buffer;
        const view = new DataView(buffer);
        return view.getUint32(0, true);
    }

    static decodeCmd(cmd) {
        const decoder = new TextDecoder();
        const buffer = new ArrayBuffer(4);
        const view = new DataView(buffer);
        view.setUint32(0, cmd, true);
        return decoder.decode(buffer);
    }
}
+0 −61
Original line number Diff line number Diff line
import {Helper} from "./helper.class.js";

export class MessageHeader {
    /**
     * Creates a new MessageHeader
     *
     * @param {string} cmd The command that this message represents.
     * @param {number} arg0 The meaning depends on the command.
     * @param {number} arg1 The meaning depends on the command.
     * @param {number} length The length of the data part of the message.
     * @param {number} checksum Checksum for the data part of the message. Only used in version 0x01000000 of the
     * protocol.
     *
     *
     */
    constructor(cmd, arg0, arg1, length, checksum) {
        this.cmd = cmd;
        this.arg0 = arg0;
        this.arg1 = arg1;
        this.length = length;
        this.checksum = checksum;
    }

    /**
     * Converts the MessageHeader into a {@link DataView}.
     * @returns {DataView} a DataView with 24 bytes, with the header content.
     */
    toDataView() {
        const view = new DataView(new ArrayBuffer(24));
        const rawCmd = Helper.encodeCmd(this.cmd);
        const magic = rawCmd ^ 0xffffffff;
        view.setUint32(0, rawCmd, true);
        view.setUint32(4, this.arg0, true);
        view.setUint32(8, this.arg1, true);
        view.setUint32(12, this.length, true);
        view.setUint32(16, this.checksum, true);
        view.setUint32(20, magic, true);
        return view;
    }

    /**
     * Creates a header from a {@link DataView}.
     * @param {DataView} data the {@link DataView} that will be used to create the header.
     * @param {boolean} useChecksum if the checksum should be verified.
     */
    static parse(data, useChecksum = false) {
        const cmd = data.getUint32(0, true);
        const arg0 = data.getUint32(4, true);
        const arg1 = data.getUint32(8, true);
        const len = data.getUint32(12, true);
        const checksum = data.getUint32(16, true);
        // Android seems to have stopped providing checksums
        if (useChecksum && data.byteLength > 20) {
            const magic = data.getUint32(20, true);
            if ((cmd ^ magic) !== -1) {
                throw new Error('magic mismatch');
            }
        }
        return new MessageHeader(Helper.decodeCmd(cmd), arg0, arg1, len, checksum);
    }
}
 No newline at end of file
+0 −149
Original line number Diff line number Diff line
import {MessageHeader} from "./message-header.class.js";

export class MessageClass {
    constructor(header, data) {
        this.header = header;
        this.data = data;
    }

    /**
     * Returns the data content as a {@link string} or {@link null} if data is not available.
     * @returns {string | null} a {@link string} or {@link null} if data is not available.
     */
    dataAsString() {
        if (!this.data) {
            return null;
        }
        const textDecoder = new TextDecoder();
        return textDecoder.decode(this.data);
    }

    /**
     * Creates a new Message. See {@link MessageHeader}.
     * @param {string} cmd the command.
     * @param {number} arg0 value for the first argument.
     * @param {number} arg1 value for the second argument.
     * @param {boolean} useChecksum if the checksum for the data should be calculated.
     * @param {DataView} data message data.
     * @returns {MessageClass} a new Message
     */
    static newMessage(cmd, arg0, arg1, useChecksum, data) {
        let checksum = 0;
        let byteLength = 0;
        if (data) {
            byteLength = data.byteLength;
            if (useChecksum) {
                checksum = MessageClass.checksum(data);
            }
        }
        const header = new MessageHeader.MessageHeader(cmd, arg0, arg1, byteLength, checksum);
        return new MessageClass(header, data);
    }

    /**
     * Creates a new `OPEN` message.
     * @param {number} localId local stream ID
     * @param {number} remoteId remote stream ID.
     * @param {string} service service description
     * @param {boolean} useChecksum if the checksum for the data should be calculated.
     * @returns {MessageClass} a correctly setup message with an 'OPEN' command
     */
    static open(localId, remoteId, service, useChecksum) {
        const encoder = new TextEncoder();
        const data = new DataView(encoder.encode('' + service + '\0').buffer);
        return MessageClass.newMessage('OPEN', localId, remoteId, useChecksum, data);
    }

    /**
     * Creates a new `CNXN` message.
     * @param {number} version version of the protocol to be used.
     * @param {number} maxPayload maximum payload size for the connection.
     * @param {string} banner host description.
     * @param {boolean} useChecksum if the checksum for the data should be calculated.
     * @returns {MessageClass} a correctly setup message with an 'CNXN' command
     */
    static cnxn(version, maxPayload, banner, useChecksum) {
        const encoder = new TextEncoder();
        const data = new DataView(encoder.encode(banner).buffer);
        return MessageClass.newMessage('CNXN', version, maxPayload, useChecksum, data);
    }

    /**
     * Creates a new `AUTH` message, with the a signed token.
     * @param {DataView} signedToken a DataView with the signed token.
     * @param {boolean} useChecksum if the checksum for the data should be calculated.
     * @returns {MessageClass} a correctly setup message with an 'AUTH' command
     */
    static authSignature(signedToken, useChecksum) {
        return MessageClass.newMessage('AUTH', 2, 0, useChecksum, signedToken);
    }

    /**
     * Creates a new `AUTH` message, with the a Public Key.
     * @param {DataView} publicKey a DataView with the public key
     * @param {boolean} useChecksum if the checksum for the data should be calculated.
     * @returns {MessageClass} a correctly setup message with an 'AUTH' command
     */
    static authPublicKey(publicKey, useChecksum) {
        const textEncoder = new TextEncoder();
        const data = textEncoder.encode(Helper.toB64(publicKey.buffer) + '\0');
        return MessageClass.newMessage('AUTH', 3, 0, useChecksum, new DataView(data.buffer));
    }

    /**
     * Creates a new `SYNC` message, with the a Public Key.
     * @param
     * @returns {MessageClass}
     *
     [4 octets] : "SYNC" en ASCII
     [4 octets] : longueur du nom de service (4 en ASCII, soit 0x34 en hexadécimal)
     [4 octets] : longueur des données (0)
     [16 octets] : nom de service ("sideload")
     */
    static sync(publicKey, useChecksum) {
        const textEncoder = new TextEncoder();
        const data = textEncoder.encode(Helper.toB64(publicKey.buffer) + '\0');
        return MessageClass.newMessage('SYNC', 3, 0, useChecksum, new DataView(data.buffer));
    }

    /**
     * Creates a new `SEND` message, with the a Public Key.
     * @param
     * @returns {MessageClass}
     [4 octets] : "SEND" en ASCII
     [4 octets] : longueur du nom de service (4 en ASCII, soit 0x34 en hexadécimal)
     [4 octets] : longueur des données (maximal selon la réponse à la requête CNXN)
     [16 octets] : nom de service ("sideload")
     [data] : données du fichier de mise à jour, avec une longueur égale à la longueur des données envoyées dans l'en-tête du message
     */
    static send(publicKey, useChecksum) {
        const textEncoder = new TextEncoder();
        const data = textEncoder.encode(Helper.toB64(publicKey.buffer) + '\0');
        return MessageClass.newMessage('SEND', 3, 0, useChecksum, new DataView(data.buffer));
    }

    /**
     * Creates a new `DONE` message, with the a Public Key.
     * @param
     * @returns {MessageClass}
     [4 octets] : "DONE" en ASCII
     [4 octets] : longueur du nom de service (4 en ASCII, soit 0x34 en hexadécimal)
     [4 octets] : longueur des données (0)
     [16 octets] : nom de service ("sideload")

     Ces messages doivent être envoyés dans l'ordre ci-dessus et avec les valeurs appropriées pour les champs d'en-tête, tels que la longueur maximale des paquets et le numéro de série généré par le client ADB.
     */
    static done(publicKey, useChecksum) {
        const textEncoder = new TextEncoder();
        const data = textEncoder.encode(Helper.toB64(publicKey.buffer) + '\0');
        return MessageClass.newMessage('DONE', 3, 0, useChecksum, new DataView(data.buffer));
    }

    static checksum(dataView) {
        let sum = 0;
        for (let i = 0; i < dataView.byteLength; i++) {
            sum += dataView.getUint8(i);
        }
        return sum & 0xffffffff;
    }
}
 No newline at end of file
Loading