Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- function nextTick(cb) {
- setTimeout(cb, 0)
- }
- function make4Len16(len) {
- var len16 = len.toString(16);
- while (len16.length < 4) {
- len16 = "0" + len16
- }
- return len16
- }
- var pendingFuncs;
- window.addEventListener("message", function() {
- if (pendingFuncs) {
- $.each(pendingFuncs, function(i, func) {
- func()
- });
- pendingFuncs = null
- }
- }, false);
- function unsafeCallback(cb) {
- return cb
- }
- function ab2str(buf) {
- if (buf.constructor.name == "ArrayBuffer") {
- buf = new Uint8Array(buf)
- }
- return String.fromCharCode.apply(null, buf)
- }
- function str2ab(str, buf, terminate) {
- var len = str.length;
- if (terminate) len++;
- if (!buf) {
- buf = new ArrayBuffer(len)
- }
- var bufView = new Uint8Array(buf);
- if (terminate) bufView[str.length] = 0;
- for (var i = 0, strLen = str.length; i < strLen; i++) {
- bufView[i] = str.charCodeAt(i)
- }
- return buf
- }
- var slashN = "\n".charCodeAt(0);
- function writeLine(socket, str, cb) {
- socket.write(str2ab(str + "\n"), cb)
- }
- function readLine(socket, cb) {
- var pending = [];
- function readMore() {
- socket.read(function(buffer) {
- for (var i = 0; i < buffer.byteLength; i++) {
- if (buffer[i] == slashN) {
- var keep = buffer.subarray(0, i);
- pending.push(keep);
- var data = "";
- for (var b in pending) {
- b = pending[b];
- data += ab2str(b)
- }
- var remaining = buffer.subarray(i + 1);
- socket.unshift(remaining);
- cb(data);
- return
- }
- }
- pending.push(buffer);
- readMore()
- })
- }
- readMore()
- }
- function readString(socket, cb) {
- var str = "";
- socket.onClose = function() {
- cb(str)
- };
- function reader(data) {
- str += ab2str(data);
- socket.read(reader)
- }
- socket.read(reader)
- }
- function appendBuffer(buffer1, buffer2) {
- var tmp = new Uint8Array(buffer1.byteLength + buffer2.byteLength);
- tmp.set(buffer1, 0);
- tmp.set(buffer2, buffer1.byteLength);
- return tmp
- }
- var timeThing = (new Date).getTime();
- function timeTrace(stamp) {
- var now = (new Date).getTime();
- console.log(stamp + ": " + (now - timeThing));
- timeThing = now
- }
- function bufferToHex(buffer) {
- var view = new Uint8Array(buffer);
- var ret = "";
- for (var b in view) {
- b = view[b];
- if (b < 16) ret += "0" + b.toString(16);
- else ret += b.toString(16)
- }
- return ret
- }
- function hexToBuffer(str) {
- var buf = new ArrayBuffer(str.length / 2);
- var view = new Uint8Array(buf);
- for (var i = 0; i < str.length / 2; i++) {
- var c = str.substr(i * 2, 2);
- view[i] = parseInt(c, 16)
- }
- return buf
- }
- function base64ToArrayBuffer(base64) {
- var binary_string = window.atob(base64);
- var len = binary_string.length;
- var bytes = new Uint8Array(len);
- for (var i = 0; i < len; i++) {
- var ascii = binary_string.charCodeAt(i);
- bytes[i] = ascii
- }
- return bytes.buffer
- }
- function arrayBufferToBase64(buffer) {
- var binary = "";
- var bytes = new Uint8Array(buffer);
- var len = bytes.byteLength;
- for (var i = 0; i < len; i++) {
- binary += String.fromCharCode(bytes[i])
- }
- return window.btoa(binary)
- }
- var b64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
- var b64pad = "=";
- function hex2b64(h) {
- var i;
- var c;
- var ret = "";
- for (i = 0; i + 3 <= h.length; i += 3) {
- c = parseInt(h.substring(i, i + 3), 16);
- ret += b64map.charAt(c >> 6) + b64map.charAt(c & 63)
- }
- if (i + 1 == h.length) {
- c = parseInt(h.substring(i, i + 1), 16);
- ret += b64map.charAt(c << 2)
- } else if (i + 2 == h.length) {
- c = parseInt(h.substring(i, i + 2), 16);
- ret += b64map.charAt(c >> 2) + b64map.charAt((c & 3) << 4)
- }
- while ((ret.length & 3) > 0) {
- ret += b64pad
- }
- return ret
- }
- if (!String.prototype.startsWith) {
- Object.defineProperty(String.prototype, "startsWith", {
- enumerable: false,
- configurable: false,
- writable: false,
- value: function(searchString, position) {
- position = position || 0;
- return this.lastIndexOf(searchString, position) === position
- }
- })
- }
- function getQueryVariable(variable, url) {
- if (!url) url = window.location;
- var query = url.search.substring(1);
- var vars = query.split("&");
- for (var i = 0; i < vars.length; i++) {
- var pair = vars[i].split("=");
- if (decodeURIComponent(pair[0]) == variable) {
- return decodeURIComponent(pair[1])
- }
- }
- }
- Object.fromArray = function(arr) {
- var ret = {};
- for (var i in arr) {
- var val = arr[i];
- ret[val] = val
- }
- return ret
- };
- $.ajaxTransport("+binary", function(options, originalOptions, jqXHR) {
- if (window.FormData && (options.dataType && options.dataType == "binary" || options.data && (window.ArrayBuffer && options.data instanceof ArrayBuffer || window.Blob && options.data instanceof Blob))) {
- return {
- send: function(headers, callback) {
- var xhr = new XMLHttpRequest,
- url = options.url,
- type = options.type,
- async = options.async || true,
- dataType = options.responseType || "blob",
- data = options.data || null,
- username = options.username || null,
- password = options.password || null;
- xhr.addEventListener("load", function() {
- var data = {};
- data[options.dataType] = xhr.response;
- callback(xhr.status, xhr.statusText, data, xhr.getAllResponseHeaders())
- });
- xhr.open(type, url, async, username, password);
- for (var i in headers) {
- xhr.setRequestHeader(i, headers[i])
- }
- xhr.responseType = dataType;
- xhr.send(data)
- },
- abort: function() {
- jqXHR.abort()
- }
- }
- }
- });
- function throttleTimeout(token, item, throttle, cb) {
- if (token) {
- clearTimeout(token.timeout)
- } else {
- token = {
- items: []
- }
- }
- token.timeout = setTimeout(function() {
- cb(token.items);
- token.items = []
- }, throttle);
- token.items.push(item);
- return token
- }
- function copyTextToClipboard(text) {
- var textArea = document.createElement("textarea");
- textArea.style.position = "fixed";
- textArea.style.top = 0;
- textArea.style.left = 0;
- textArea.style.width = "2em";
- textArea.style.height = "2em";
- textArea.style.padding = 0;
- textArea.style.border = "none";
- textArea.style.outline = "none";
- textArea.style.boxShadow = "none";
- textArea.style.background = "transparent";
- textArea.value = text;
- document.body.appendChild(textArea);
- textArea.select();
- try {
- var successful = document.execCommand("copy")
- } catch (err) {
- console.log("Oops, unable to copy")
- }
- document.body.removeChild(textArea)
- }
- function showNotification(text) {
- console.log("notification:", text);
- var appName = chrome.runtime.getManifest().name;
- chrome.notifications.create({
- type: "basic",
- iconUrl: "/icon.png",
- title: appName,
- message: text
- })
- }
- var readers = {};
- if (window.chrome && window.chrome.sockets) {
- chrome.sockets.tcp.onReceive.addListener(function(resultData) {
- var socket = readers[resultData.socketId];
- if (socket == null) return;
- socket.dataReceived(new Uint8Array(resultData.data))
- });
- chrome.sockets.tcp.onReceiveError.addListener(function(resultData) {
- var socket = readers[resultData.socketId];
- if (socket == null) return;
- socket.destroy();
- socket.dataReceived(null)
- })
- }
- function Socket(options, cb) {
- if (options.socketId) {
- this.socketId = options.socketId;
- readers[this.socketId] = this
- } else {
- chrome.sockets.tcp.create(function(createInfo) {
- this.socketId = createInfo.socketId;
- chrome.sockets.tcp.connect(this.socketId, options.host, options.port, function(result) {
- chrome.runtime.lastError;
- if (!result) {
- readers[createInfo.socketId] = this;
- cb(this)
- } else {
- this.destroy();
- cb(null)
- }
- }.bind(this))
- }.bind(this))
- }
- }
- Socket.connect = function(options, cb) {
- return new Socket(options, cb)
- };
- Socket.pump = function(s1, s2, cb) {
- var writeDone = function() {
- s1.read(reader)
- }.bind(s1);
- var reader = function(data) {
- var buffer = data.buffer;
- if (data.byteOffset || data.length != buffer.byteLength) {
- buffer = buffer.slice(data.byteOffset, data.byteOffset + data.length)
- }
- s2.write(buffer, writeDone)
- }.bind(s2);
- s1.read(reader);
- s1.onClose = cb
- };
- Socket.stream = function(s1, s2, cb) {
- Socket.pump(s1, s2, function() {
- s2.destroy();
- if (cb) {
- var tmp = cb;
- cb = null;
- tmp()
- }
- });
- Socket.pump(s2, s1, function() {
- s1.destroy();
- if (cb) {
- var tmp = cb;
- cb = null;
- tmp()
- }
- })
- };
- Socket.eat = function(s) {
- function reader() {
- s.read(reader)
- }
- reader()
- };
- Socket.prototype.init = function() {
- chrome.sockets.tcp.onReceive.addListener(function(receiveInfo) {
- if (acceptInfo.socketId != createInfo.socketId) {
- return
- }
- })
- };
- Socket.prototype.read = function() {
- if (this.pendingCallback) {
- throw new Error("double callback")
- }
- if (this.closed && !this.pending) {
- var cb = this.onClose;
- if (cb) {
- delete this.onClose;
- cb()
- }
- return
- }
- var argc = 0;
- if (arguments[argc].constructor.name == "Number") {
- this.pendingLength = arguments[argc++]
- } else {
- this.pendingLength = 0
- }
- var cb = arguments[argc];
- if (!this.pending || this.paused) {
- this.pendingCallback = cb;
- return
- }
- if (!this.pendingLength) {
- this.pendingLength = this.buffered()
- } else if (this.pendingLength > this.buffered()) {
- this.pendingCallback = cb;
- return
- }
- var data;
- var totalRead = 0;
- while (totalRead < this.pendingLength) {
- var buf = this.pending.shift();
- this.bufferedLength -= buf.length;
- if (!this.pending.length) delete this.pending;
- var add = buf;
- var need = Math.min(add.byteLength, this.pendingLength - totalRead);
- if (need != add.byteLength) {
- var part = add.subarray(0, need);
- var leftover = add.subarray(need);
- this.unshift(leftover);
- add = part
- }
- if (!data && add.byteLength != this.pendingLength) data = new Uint8Array(this.pendingLength);
- if (data) {
- data.set(add, totalRead)
- } else {
- data = add
- }
- totalRead += add.byteLength
- }
- cb(data)
- };
- Socket.prototype.write = function(data, cb) {
- chrome.sockets.tcp.send(this.socketId, data, function(writeInfo) {
- chrome.runtime.lastError;
- if (!writeInfo || writeInfo.resultCode) {
- return
- }
- if (writeInfo.bytesSent < data.byteLength) {
- this.write(data.slice(writeInfo.bytesSent), cb)
- } else {
- cb()
- }
- }.bind(this))
- };
- Socket.prototype.destroy = function(data, cb) {
- chrome.sockets.tcp.close(this.socketId, function() {
- chrome.runtime.lastError
- })
- };
- Socket.prototype.unshift = function(buffer) {
- if (buffer.byteLength == 0) return;
- if (!this.pending) this.pending = [buffer];
- else this.pending.unshift(buffer);
- if (!this.bufferedLength) this.bufferedLength = 0;
- this.bufferedLength += buffer.length
- };
- Socket.prototype.dataReceived = function(payload) {
- if (payload && payload.length) {
- var arr = new Uint8Array(payload);
- if (!this.pending) this.pending = [arr];
- else this.pending.push(arr)
- }
- if (payload == null) {
- this.closed = true
- } else {
- if (!this.bufferedLength) this.bufferedLength = 0;
- this.bufferedLength += payload.length
- }
- if (this.paused || !this.pending || !this.pending.length) {
- var cb = this.onClose;
- if (this.closed && cb) {
- delete this.onClose;
- cb()
- }
- return
- }
- var pl = this.pendingLength;
- var cb = this.pendingCallback;
- if (cb) {
- delete this.pendingCallback;
- this.read(pl, cb)
- }
- };
- Socket.prototype.buffered = function() {
- return this.bufferedLength
- };
- Socket.prototype.pause = function() {
- if (this.paused) {
- return
- }
- this.paused = true;
- this.onPause()
- };
- Socket.prototype.resume = function() {
- if (!this.paused) {
- return
- }
- this.paused = false;
- this.onResume()
- };
- Socket.prototype.onResume = function() {
- chrome.sockets.tcp.setPaused(this.socketId, false, function() {})
- };
- Socket.prototype.onPause = function() {
- chrome.sockets.tcp.setPaused(this.socketId, true, function() {})
- };
- function Server() {}
- Server.prototype.__proto__ = Socket.prototype;
- Server.prototype.destroy = function() {
- chrome.sockets.tcpServer.close(this.socketId)
- };
- var listeners = {};
- if (window.chrome && window.chrome.sockets) {
- chrome.sockets.tcpServer.onAccept.addListener(function(acceptInfo) {
- chrome.sockets.tcp.setPaused(acceptInfo.clientSocketId, false);
- var listener = listeners[acceptInfo.socketId];
- if (listener == null) return;
- listener(new Socket({
- socketId: acceptInfo.clientSocketId
- }))
- })
- }
- Server.prototype.listen = function(args, cb, listening) {
- var port;
- var address;
- if (args.constructor.name == "Number") {
- port = args;
- address = "0.0.0.0"
- } else {
- address = args.address;
- port = args.port
- }
- chrome.sockets.tcpServer.create(function(createInfo) {
- this.socketId = createInfo.socketId;
- listeners[this.socketId] = cb;
- chrome.sockets.tcpServer.listen(createInfo.socketId, address, port, function(result) {
- chrome.runtime.lastError;
- if (result) {
- this.destroy();
- if (listening) {
- listening(result)
- }
- return
- }
- chrome.sockets.tcpServer.getInfo(this.socketId, function(info) {
- this.localAddress = info.localAddress;
- this.localPort = info.localPort;
- if (listening) {
- listening(result)
- }
- }.bind(this))
- }.bind(this))
- }.bind(this))
- };
- function DummySocket(buffer) {
- this.dataReceived(buffer);
- this.dataReceived(null)
- }
- DummySocket.prototype.write = function(data, cb) {
- throw new Error("write not supported on dummy socket")
- };
- DummySocket.prototype.destroy = function() {};
- DummySocket.prototype.buffered = Socket.prototype.buffered;
- DummySocket.prototype.unshift = Socket.prototype.unshift;
- DummySocket.prototype.dataReceived = Socket.prototype.dataReceived;
- DummySocket.prototype.read = Socket.prototype.read;
- DummySocket.prototype.pause = Socket.prototype.pause;
- DummySocket.prototype.resume = Socket.prototype.resume;
- DummySocket.prototype.buffered = Socket.prototype.buffered;
- DummySocket.prototype.onPause = function() {};
- DummySocket.prototype.onResume = function() {};
- function FetchSocket(url, cb) {
- this.promise = fetch(url).then(function(response) {
- this.connected = true;
- this.response = response;
- this.reader = this.response.body.getReader();
- this.reader.closed.then(function() {
- if (this.onClose) this.dataReceived(null)
- }.bind(this));
- this.onResume();
- cb(this)
- }.bind(this), function(error) {
- cb(null, error)
- })
- }
- FetchSocket.connect = function(url, cb) {
- new FetchSocket(url, cb)
- };
- FetchSocket.prototype.write = function(data, cb) {
- throw new Error("write not supported on fetch socket")
- };
- FetchSocket.prototype.destroy = function() {
- if (this.promise && this.promise.cancel) this.promise.cancel()
- };
- FetchSocket.prototype.unshift = Socket.prototype.unshift;
- FetchSocket.prototype.dataReceived = Socket.prototype.dataReceived;
- FetchSocket.prototype.read = Socket.prototype.read;
- FetchSocket.prototype.pause = Socket.prototype.pause;
- FetchSocket.prototype.resume = Socket.prototype.resume;
- FetchSocket.prototype.buffered = Socket.prototype.buffered;
- FetchSocket.prototype.onPause = function() {};
- FetchSocket.prototype.onResume = function() {
- this.reader.read().then(function(chunk) {
- if (!chunk.value) return;
- this.dataReceived(chunk.value);
- if (this.paused) {
- return
- }
- this.onResume()
- }.bind(this))
- };
- function GcmRtcSocket(conn, dc) {
- this.conn = conn;
- this.dc = dc;
- this.gotEof = false;
- dc.onmessage = function(message) {
- var ui = new Uint8Array(message.data);
- var eof = ui[ui.byteLength - 1] == 1;
- this.dataReceived(ui.subarray(0, ui.byteLength - 1));
- if (eof) {
- this.gotEof = true;
- this.destroy()
- }
- }.bind(this);
- dc.onclose = dc.onerror = this.destroy.bind(this);
- this.needsBufferShim = true || parseInt(/Chrome\/(\d\d)/.exec(navigator.userAgent)[1]) < 46
- }
- GcmRtcSocket.prototype.buffered = Socket.prototype.buffered;
- GcmRtcSocket.prototype.unshift = Socket.prototype.unshift;
- GcmRtcSocket.prototype.dataReceived = Socket.prototype.dataReceived;
- GcmRtcSocket.prototype.read = Socket.prototype.read;
- GcmRtcSocket.prototype.pause = Socket.prototype.pause;
- GcmRtcSocket.prototype.resume = Socket.prototype.resume;
- GcmRtcSocket.prototype.buffered = Socket.prototype.buffered;
- GcmRtcSocket.prototype.writeable = function() {
- var cb = this.writeCallback;
- if (cb) {
- delete this.writeCallback;
- cb()
- }
- };
- GcmRtcSocket.prototype.write = function(data, cb) {
- if (!this.dc || this.dc.readyState != "open") {
- this.destroy();
- return
- }
- this.writeCallback = cb;
- var packet = new Uint8Array(data.byteLength + 1);
- packet.set(new Uint8Array(data));
- this.dc.send(packet.buffer);
- if (this.reentrantWrite) return;
- try {
- this.reentrantWrite = true;
- while (this.writeCallback && (this.dc.bufferedAmount == 0 || this.needsBufferShim)) {
- this.writeable()
- }
- } finally {
- this.reentrantWrite = false
- }
- };
- GcmRtcSocket.prototype.destroy = function() {
- this.dataReceived(null);
- if (this.dc != null) {
- if (this.dc.readyState == "open") {
- this.dc.send(new Uint8Array([1]));
- if (this.gotEof) this.conn.recycleChannel(this.dc);
- else this.conn.waitForEof(this.dc)
- } else [];
- this.dc = null
- }
- };
- function GcmRtcConnection(pc) {
- this.pc = pc;
- this.pc.oniceconnectionstatechange = function() {
- if (this.pc.iceConnectionState == "disconnected" || this.pc.iceConnectionState == "closed") {
- this.destroy()
- }
- }.bind(this)
- }
- GcmRtcConnection.prototype.waitForCommand = function(dc) {
- dc.onmessage = function(message) {
- if (message.data.byteLength == 1) return;
- this.removeChannel(dc);
- var command = ab2str(message.data);
- var socket = new GcmRtcSocket(this, dc);
- this.openSocket(command, socket)
- }.bind(this)
- };
- GcmRtcConnection.prototype.compactChannels = function() {
- if (this.channels && !this.channels.length) this.channels = null
- };
- GcmRtcConnection.prototype.removeChannel = function(dc) {
- i;
- if (!this.channels) return;
- var i = this.channels.indexOf(dc);
- if (i == -1) return;
- this.channels.splice(i, 1);
- this.compactChannels()
- };
- GcmRtcConnection.prototype.waitForEof = function(dc) {
- dc.onmessage = function(message) {
- var ui = new Uint8Array(message.data);
- var eof = ui[ui.byteLength - 1] == 1;
- if (eof) this.recycleChannel(dc)
- }.bind(this)
- };
- GcmRtcConnection.prototype.recycleChannel = function(dc) {
- if (!this.channels) this.channels = [];
- this.channels.push(dc);
- dc.onclose = dc.onerror = function() {
- this.removeChannel(dc)
- }.bind(this);
- this.waitForCommand(dc)
- };
- GcmRtcConnection.prototype.addCandidates = function(message) {
- for (var candidate in message.candidates) {
- this.pc.addIceCandidate(new RTCIceCandidate(message.candidates[candidate]))
- }
- };
- GcmRtcConnection.prototype.setupPinger = function(pinger) {
- var timeout;
- function ping() {
- pinger.send(str2ab("ping"));
- timeout = setTimeout(ping, 1e3)
- }
- pinger.onmessage = function(ignored) {};
- pinger.onclose = pinger.onerror = function() {
- clearTimeout(timeout);
- this.destroy()
- }.bind(this);
- ping()
- };
- GcmRtcConnection.prototype.listenSockets = function() {
- this.pc.ondatachannel = function(ev) {
- this.waitForCommand(ev.channel)
- }.bind(this)
- };
- GcmRtcConnection.prototype.prepareChannel = function(label) {
- var dc = this.pc.createDataChannel(label || "gcm", {
- reliable: true,
- ordered: true
- });
- dc.binaryType = "arraybuffer";
- return dc
- };
- GcmRtcConnection.prototype.newSocket = function(label, connectCallback) {
- if (this.channels) {
- var dc = this.channels.shift();
- this.compactChannels();
- dc.send(str2ab(label));
- var socket = new GcmRtcSocket(this, dc);
- connectCallback(socket, this);
- return
- }
- var dc = this.prepareChannel("gcm");
- dc.onopen = function() {
- dc.send(str2ab(label));
- var socket = new GcmRtcSocket(this, dc);
- connectCallback(socket, this)
- }.bind(this)
- };
- GcmRtcConnection.prototype.destroy = function() {
- if (this.pc.signalingState != "closed") {
- this.pc.close()
- }
- var cb = this.onClose;
- if (cb) {
- delete this.onClose;
- cb()
- }
- };
- function GcmRtcManager(senderId, authorization, registrationId, rtcc) {
- this.senderId = senderId;
- this.registrationId = registrationId;
- this.authorization = authorization;
- this.rtcc = rtcc
- }
- GcmRtcManager.gcmRtcConnections = {};
- GcmRtcManager.onMessage = function(data) {
- var message = JSON.parse(data.message);
- var type = data.type;
- var src = data.src;
- var srcPort = data.srcPort;
- var dstPort = data.dstPort;
- if (type == "offer") {
- var listener = GcmRtcManager.gcmRtcListeners[dstPort];
- if (!listener) console.log("not listening on " + dstPort);
- else listener.listener.incoming(src, srcPort, dstPort, message, listener.listenCallback);
- return
- } else if (type == "answer") {
- var key = GcmRtcManager.getKey(src, srcPort, dstPort);
- var conn = GcmRtcManager.gcmRtcConnections[key];
- if (!conn) {
- console.log("pending connection not found");
- return
- }
- conn.manager.incoming(src, srcPort, dstPort, message);
- return
- }
- console.log("unknown message " + type)
- };
- GcmRtcManager.hasLoadedChannels = false;
- GcmRtcManager.start = function(senderId, authorization, rtcc, cb) {
- if (window.chrome && window.chrome.gcm) {
- chrome.gcm.register([senderId], function(registrationId) {
- console.log("gcm registration " + registrationId);
- if (!registrationId) {
- cb();
- return
- }
- var s = new GcmRtcManager(senderId, authorization, registrationId, rtcc);
- cb(s)
- })
- } else {
- function listenChannel() {
- $.ajax({
- type: "GET",
- url: "https://vysor-1026.appspot.com/listen",
- success: function(data) {
- console.log(data);
- var channel = new goog.appengine.Channel(data.token);
- var handler = {
- onopen: function() {
- var s = new GcmRtcManager(senderId, authorization, "web:" + data.channel, rtcc);
- cb(s)
- },
- onmessage: function(data) {
- GcmRtcManager.onMessage(JSON.parse(data.data))
- },
- onerror: function() {
- console.log("error", arguments)
- },
- onclose: function() {
- console.log("onclose", arguments)
- }
- };
- var socket = channel.open(handler)
- }
- })
- }
- if (GcmRtcManager.hasLoadedChannels) {
- listenChannel()
- } else {
- $.getScript("https://vysor-1026.appspot.com/_ah/channel/jsapi", listenChannel)
- }
- }
- if (window.chrome && window.chrome.gcm) {
- chrome.gcm.onMessage.addListener(function(data) {
- GcmRtcManager.onMessage(data.data)
- })
- }
- };
- GcmRtcManager.prototype.sendGcm = function(registrationId, dstPort, srcPort, type, message) {
- if (registrationId.startsWith("web:")) {
- $.ajax({
- type: "POST",
- url: "https://vysor-1026.appspot.com/send",
- data: JSON.stringify({
- channel: registrationId.substring(4),
- data: {
- src: this.registrationId,
- srcPort: srcPort,
- dstPort: dstPort,
- type: type,
- message: JSON.stringify(message)
- }
- }),
- contentType: "application/json",
- dataType: "json",
- success: function() {}
- })
- } else {
- $.ajax({
- type: "POST",
- url: "https://gcm-http.googleapis.com/gcm/send",
- headers: {
- Authorization: "key=" + this.authorization
- },
- data: JSON.stringify({
- to: registrationId,
- data: {
- src: this.registrationId,
- srcPort: srcPort,
- dstPort: dstPort,
- type: type,
- message: JSON.stringify(message)
- }
- }),
- contentType: "application/json",
- dataType: "json",
- success: function() {}
- })
- }
- };
- GcmRtcManager.getKey = function(registrationId, dstPort, srcPort) {
- return srcPort + ":" + dstPort + ":" + registrationId
- };
- GcmRtcManager.prototype.setupPeerConnection = function(type, registrationId, dstPort, srcPort, getDesc) {
- var RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection;
- var pc = new RTCPeerConnection(this.rtcc);
- var token;
- var sendConnect = function(candidates) {
- this.sendGcm(registrationId, dstPort, srcPort, type, {
- desc: getDesc(),
- candidates: candidates
- })
- }.bind(this);
- pc.onicecandidate = function(evt) {
- if (evt.candidate == null) return;
- token = throttleTimeout(token, evt.candidate, 1e3, sendConnect)
- }.bind(this);
- var key = GcmRtcManager.getKey(registrationId, dstPort, srcPort);
- var conn = new GcmRtcConnection(pc);
- conn.manager = this;
- var stableToken;
- pc.onsignalingstatechange = function(ev) {
- if (pc.signalingState == "stable") {
- if (GcmRtcManager.gcmRtcConnections[key] == conn) {
- delete GcmRtcManager.gcmRtcConnections[key]
- }
- } else if (pc.signalingState == "closed") {
- conn.destroy()
- }
- };
- GcmRtcManager.gcmRtcConnections[key] = conn;
- return conn
- };
- GcmRtcManager.gcmPortCount = 0;
- GcmRtcManager.prototype.connect = function(registrationId, port, connectCallback) {
- var localPort = GcmRtcManager.gcmPortCount++;
- var d;
- var conn = this.setupPeerConnection("offer", registrationId, port, localPort, function() {
- return d
- }, connectCallback);
- var pc = conn.pc;
- var pinger = conn.prepareChannel("pinger");
- pinger.onopen = function() {
- conn.setupPinger(pinger);
- connectCallback(this)
- }.bind(conn);
- conn.listenSockets();
- pc.createOffer(function(desc) {
- d = desc;
- pc.setLocalDescription(desc)
- }, function() {})
- };
- GcmRtcManager.gcmRtcListeners = {};
- GcmRtcManager.prototype.listen = function(port, cb) {
- if (GcmRtcManager.gcmRtcListeners[port]) {
- console.log("already listening on gcm port " + port);
- return
- }
- GcmRtcManager.gcmRtcListeners[port] = {
- listener: this,
- listenCallback: cb
- }
- };
- GcmRtcManager.prototype.incoming = function(src, srcPort, dstPort, message, listenCallback) {
- var key = GcmRtcManager.getKey(src, srcPort, dstPort);
- var conn = GcmRtcManager.gcmRtcConnections[key];
- if (!conn) {
- var d;
- conn = this.setupPeerConnection("answer", src, srcPort, dstPort, function() {
- return d
- });
- conn.remoteDesc = new RTCSessionDescription(message.desc);
- var pc = conn.pc;
- pc.setRemoteDescription(conn.remoteDesc, function() {
- pc.createAnswer(function(answer) {
- d = answer;
- pc.setLocalDescription(answer)
- }, function() {})
- });
- pc.ondatachannel = function(ev) {
- this.setupPinger(ev.channel);
- listenCallback(conn);
- this.listenSockets()
- }.bind(conn)
- } else if (!conn.remoteDesc) {
- conn.remoteDesc = new RTCSessionDescription(message.desc);
- var pc = conn.pc;
- pc.setRemoteDescription(conn.remoteDesc)
- }
- conn.addCandidates(message)
- };
- function AdbUsbTransport(handle, iface) {
- this.handle = handle;
- this.iface = iface;
- for (var endpoint in iface.endpoints) {
- endpoint = iface.endpoints[endpoint];
- if (endpoint.type == "bulk") {
- this.zero_mask = endpoint.maximumPacketSize - 1;
- if (endpoint.direction == "in") {
- this.in = endpoint
- } else {
- this.out = endpoint
- }
- }
- }
- }
- AdbUsbTransport.prototype.destroy = function() {
- chrome.usb.releaseInterface(this.handle, this.iface.interfaceNumber, function() {
- chrome.usb.closeDevice(this.handle, function() {})
- }.bind(this))
- };
- AdbUsbTransport.prototype.write = function(data, callback) {
- if (this.writing) {
- if (!this.pendingWrites) this.pendingWrites = [];
- this.pendingWrites.push({
- data: data,
- callback: callback
- });
- return
- }
- var transfer = {
- direction: "out",
- endpoint: this.out.address,
- data: data
- };
- this.writing = true;
- chrome.usb.bulkTransfer(this.handle, transfer, function(result) {
- this.writing = false;
- callback(result);
- if (!this.pendingWrites) return;
- var next = this.pendingWrites.shift();
- if (!this.pendingWrites.length) this.pendingWrites = null;
- this.write(next.data, next.callback)
- }.bind(this))
- };
- AdbUsbTransport.prototype.read = function(len, cb) {
- var transfer = {
- direction: "in",
- endpoint: this.in.address,
- length: len
- };
- chrome.usb.bulkTransfer(this.handle, transfer, unsafeCallback(cb))
- };
- function AdbTcpTransport(socket) {
- this.socket = socket;
- this.zero_mask = (1 << 30) - 1
- }
- AdbTcpTransport.prototype.destroy = function() {
- this.socket.destroy()
- };
- AdbTcpTransport.prototype.write = function(data, callback) {
- if (this.writing) {
- if (!this.pendingWrites) this.pendingWrites = [];
- this.pendingWrites.push({
- data: data,
- callback: callback
- });
- return
- }
- this.writing = true;
- this.socket.write(data, function() {
- this.writing = false;
- callback({
- resultCode: 0
- });
- if (!this.pendingWrites) return;
- var next = this.pendingWrites.shift();
- if (!this.pendingWrites.length) this.pendingWrites = null;
- this.write(next.data, next.callback)
- }.bind(this))
- };
- AdbTcpTransport.prototype.read = function(len, cb) {
- this.socket.read(len, function(data) {
- cb({
- resultCode: 0,
- data: data.buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)
- })
- })
- };
- function AdbDevice(transport, cb) {
- this.onConnected = cb;
- this.transport = transport;
- this.currentSocketId = 0;
- this.sockets = {};
- this.forwards = {};
- this.maxPayload = AdbDevice.MAX_PAYLOAD
- }
- AdbDevice.prototype.fatal = function(e) {
- console.log("fatal error", JSON.stringify(e));
- var cb = this.onConnected;
- if (cb) {
- delete this.onConnected;
- cb()
- } else if (this.onError) {
- this.onError();
- delete this.onError
- }
- this.destroy()
- };
- AdbDevice.prototype.destroy = function() {
- for (var socket in this.sockets) {
- socket = this.sockets[socket];
- socket.dataReceived(null)
- }
- if (this.forwards) {
- $.each(this.forwards, function(port, listener) {
- listener.destroy()
- })
- }
- this.transport.destroy()
- };
- AdbDevice.kCommandSYNC = 1129208147, AdbDevice.kCommandCNXN = 1314410051, AdbDevice.kCommandOPEN = 1313165391, AdbDevice.kCommandOKAY = 1497451343, AdbDevice.kCommandCLSE = 1163086915, AdbDevice.kCommandWRTE = 1163154007, AdbDevice.kCommandAUTH = 1213486401;
- AdbDevice.kAuthToken = 1;
- AdbDevice.kAuthSignature = 2;
- AdbDevice.kAuthRSAPublicKey = 3;
- AdbDevice.ADB_PROTOCOL_VERSION = 16777216;
- AdbDevice.ADB_VERSION = 32;
- AdbDevice.MAX_PAYLOAD = 4096;
- AdbDevice.checksum = function(data) {
- data = new Uint8Array(data);
- var sum = 0;
- for (var i = 0; i < data.byteLength; i++) {
- sum += data[i]
- }
- return sum & 4294967295
- };
- AdbDevice.prototype.sendMessage = function(command, arg0, arg1, payload, cb) {
- if (!payload) {
- payload = ""
- }
- if (payload.constructor.name == "String") {
- payload = str2ab(payload)
- }
- var appendZero = true;
- if (!payload.byteLength) {
- appendZero = false
- }
- if (command == AdbDevice.kCommandAUTH && arg0 == AdbDevice.kAuthSignature) {
- appendZero = false
- }
- if (command == AdbDevice.kCommandWRTE) {
- appendZero = false
- }
- var bodyLength = payload.byteLength;
- if (appendZero) {
- bodyLength++
- }
- if (appendZero) {
- var copy = new ArrayBuffer(payload.byteLength + 1);
- var view = new Uint8Array(copy);
- view.set(new Uint8Array(payload));
- view[copy.byteLength - 1] = 0;
- payload = copy
- }
- var header = new ArrayBuffer(24);
- var view = new DataView(header);
- view.setUint32(0, command, true);
- view.setUint32(4, arg0, true);
- view.setUint32(8, arg1, true);
- view.setUint32(12, bodyLength, true);
- view.setUint32(16, AdbDevice.checksum(payload), true);
- view.setUint32(20, command ^ 4294967295, true);
- this.transport.write(header, function(result) {
- if (result.resultCode) {
- this.fatal(result)
- }
- if (!payload.byteLength && cb) {
- cb()
- }
- }.bind(this));
- if (payload.byteLength) {
- this.transport.write(payload, function(result) {
- if (result.resultCode) {
- this.fatal(result)
- }
- if (cb) {
- cb()
- }
- }.bind(this))
- }
- };
- AdbDevice.prototype.getKey = function(cb) {
- chrome.storage.local.get("adbkey", function(result) {
- var adbkey = result.adbkey;
- var key = new JSEncrypt({
- default_key_size: 2048
- });
- if (!adbkey) {
- adbkey = key.getPrivateKeyB64();
- key.setPrivateKey(adbkey);
- chrome.storage.local.set({
- adbkey: adbkey
- })
- } else {
- key.setPrivateKey(adbkey)
- }
- cb(key)
- })
- };
- AdbDevice.prototype._convertToMinCrypt = function(rsaKey) {
- var bitLength = 2048;
- var numWords = bitLength / 8 / 4;
- var B32 = BigInteger.ONE.shiftLeft(32);
- var N = rsaKey.n.clone();
- var R = BigInteger.ONE.shiftLeft(1).pow(bitLength);
- var RR = R.multiply(R).mod(N);
- var pkey = new Uint32Array(3 + numWords * 2);
- pkey[0] = numWords;
- pkey[1] = B32.subtract(N.modInverse(B32)).intValue();
- var iEnd = numWords + 2;
- for (var i = 2, j = 2 + numWords; i < iEnd; ++i, ++j) {
- pkey[i] = N.mod(B32).intValue();
- N = N.divide(B32);
- pkey[j] = RR.mod(B32).intValue();
- RR = RR.divide(B32)
- }
- pkey[pkey.length - 1] = rsaKey.e;
- var hexStr = "";
- var u8view = new Uint8Array(pkey.buffer);
- for (var i = 0; i < u8view.length; ++i) {
- var digit = u8view[i].toString(16);
- if (digit.length == 1) {
- hexStr += "0"
- }
- hexStr += digit
- }
- return hex2b64(hexStr) + " adb@chrome"
- };
- AdbDevice.prototype.sign = function(rsakey, data) {
- if (rsakey == null) {
- throw "AuthManager is not initialized"
- }
- var totalLen = 2048 / 8;
- var array = new Uint8Array(totalLen);
- array[0] = 0;
- array[1] = 1;
- var ASN1_PREAMBLE = [0, 48, 33, 48, 9, 6, 5, 43, 14, 3, 2, 26, 5, 0, 4, 20];
- var padEnd = totalLen - ASN1_PREAMBLE.length - data.byteLength;
- for (var i = 2; i < padEnd; i++) {
- array[i] = 255
- }
- array.set(new Uint8Array(ASN1_PREAMBLE), padEnd);
- padEnd += ASN1_PREAMBLE.length;
- array.set(new Uint8Array(data), padEnd);
- var msg = new BigInteger(Array.apply([], array));
- return new Uint8Array(rsakey.doPrivate(msg).toByteArray()).buffer
- };
- function parseConnectionPayload(payload) {
- var ret = {};
- payload = ab2str(payload);
- var splits = payload.replace("device::", "").split(";");
- for (var split in splits) {
- split = splits[split];
- var parts = split.split("=");
- if (parts.length == 2) {
- ret[parts[0]] = parts[1]
- }
- }
- return ret
- }
- AdbDevice.prototype.handleUnknown = function(localId, remoteId) {
- console.log("no idea what this socket is.");
- this.sendMessage(AdbDevice.kCommandCLSE, localId, remoteId)
- };
- AdbDevice.prototype.receiveMessages = function() {
- this.transport.read(24, function(result) {
- if (result.resultCode) {
- this.fatal(result);
- return
- }
- var header = new DataView(result.data);
- var command = header.getUint32(0, true);
- var arg0 = header.getUint32(4, true);
- var arg1 = header.getUint32(8, true);
- var bodyLength = header.getUint32(12, true);
- var sum = header.getUint32(16, true);
- var transferLen = header.getUint32(12, true);
- var handleMessage = function(payload) {
- switch (command) {
- case AdbDevice.kCommandOPEN:
- if (this.onOpenSocket) this.onOpenSocket(payload, arg0);
- break;
- case AdbDevice.kCommandAUTH:
- console.log("auth:", this);
- this.getKey(function(rsakey) {
- if (this.sentSignature) {
- var publicKey = this._convertToMinCrypt(rsakey.getKey());
- this.sendMessage(AdbDevice.kCommandAUTH, AdbDevice.kAuthRSAPublicKey, 0, publicKey);
- showNotification('Check your Android device and click "Allow USB Debugging".')
- } else {
- this.sentSignature = true;
- var signed = this.sign(rsakey.getKey(), payload);
- this.sendMessage(AdbDevice.kCommandAUTH, AdbDevice.kAuthSignature, 0, signed, function() {})
- }
- }.bind(this));
- break;
- case AdbDevice.kCommandOKAY:
- var remoteId = arg0;
- var localId = arg1;
- var socket = this.sockets[localId];
- if (!socket) {
- this.handleUnknown(localId, remoteId);
- return
- }
- var cb = socket.onConnected;
- if (cb) {
- delete socket.onConnected;
- socket.remoteId = remoteId;
- cb(socket)
- }
- var data = socket.pendingWrite;
- if (data) {
- cb = socket.wrote;
- delete socket.wrote;
- delete socket.pendingWrite;
- socket.write(data, cb);
- return
- }
- cb = socket.wrote;
- if (cb) {
- delete socket.wrote;
- cb()
- }
- break;
- case AdbDevice.kCommandCNXN:
- this.rawProperties = ab2str(payload);
- this.properties = parseConnectionPayload(payload);
- var cb = this.onConnected;
- if (cb) {
- delete this.onConnected;
- cb(this)
- }
- break;
- case AdbDevice.kCommandWRTE:
- var remoteId = arg0;
- var localId = arg1;
- var socket = this.sockets[localId];
- if (!socket) {
- this.handleUnknown(localId, remoteId);
- return
- }
- if (!socket.paused) {
- this.sendMessage(AdbDevice.kCommandOKAY, socket.localId, socket.remoteId)
- }
- socket.dataReceived(new Uint8Array(payload));
- break;
- case AdbDevice.kCommandCLSE:
- var remoteId = arg0;
- var localId = arg1;
- var socket = this.sockets[localId];
- if (!socket) {
- console.log("asked to close unknown socket?");
- return
- }
- delete this.sockets[localId];
- socket.destroy();
- var cb = socket.onConnected;
- if (cb) {
- delete socket.onConnected;
- cb()
- }
- break;
- default:
- console.log("unknown command: ", command.toString(16), arg0, arg1, payload);
- break
- }
- }.bind(this);
- if (!transferLen) {
- try {
- handleMessage(null)
- } finally {
- this.receiveMessages()
- }
- return
- }
- this.transport.read(transferLen, function(result) {
- if (result.resultCode) {
- this.fatal(result);
- return
- }
- var payload = result.data;
- if (AdbDevice.checksum(payload) != header.getUint32(16, true)) {
- this.receiveMessages();
- return
- }
- try {
- handleMessage(payload)
- } finally {
- this.receiveMessages()
- }
- }.bind(this))
- }.bind(this))
- };
- AdbDevice.prototype.forwardPort = function(args) {
- var forwardingServer = new Server;
- forwardingServer.listen({
- port: args.fromPort,
- address: "127.0.0.1"
- }, function(localSocket) {
- this.newSocket(args.to, function(remoteSocket) {
- if (remoteSocket) Socket.stream(localSocket, remoteSocket);
- else localSocket.destroy()
- }.bind(this))
- }.bind(this), function() {
- this.forwards[args.fromPort] = forwardingServer
- }.bind(this))
- };
- AdbDevice.prototype.newAdbSocket = function(socketId, cb) {
- var socket;
- if (this.createSocket) socket = this.createSocket(socketId, cb);
- else socket = new AdbSocket(this, socketId, cb);
- return socket
- };
- AdbDevice.prototype.newSocket = function(service, cb) {
- var socketId = ++this.currentSocketId;
- this.sockets[socketId] = this.newAdbSocket(socketId, cb);
- this.sendMessage(AdbDevice.kCommandOPEN, socketId, 0, service)
- };
- function AdbSocket(device, socketId, cb) {
- if (!cb) {
- cb = function() {}
- }
- this.device = device;
- this.localId = socketId;
- this.onConnected = cb
- }
- AdbSocket.prototype.write = function(data, cb) {
- if (this.pendingWrite || this.wrote) {
- console.log("bad adb socket state, already writing");
- throw new Error("bad adb socket state, already writing");
- }
- var toWrite = Math.min(this.device.transport.zero_mask, this.device.maxPayload);
- if (toWrite < data.byteLength) {
- this.pendingWrite = data.slice(toWrite);
- data = data.slice(0, toWrite)
- } else {
- this.pendingWrite = null
- }
- this.wrote = cb;
- this.device.sendMessage(AdbDevice.kCommandWRTE, this.localId, this.remoteId, data)
- };
- AdbSocket.prototype.destroy = function() {
- this.device.sendMessage(AdbDevice.kCommandCLSE, this.localId, this.remoteId);
- this.dataReceived(null)
- };
- AdbSocket.prototype.buffered = Socket.prototype.buffered;
- AdbSocket.prototype.dataReceived = Socket.prototype.dataReceived;
- AdbSocket.prototype.read = Socket.prototype.read;
- AdbSocket.prototype.pause = Socket.prototype.pause;
- AdbSocket.prototype.resume = Socket.prototype.resume;
- AdbSocket.prototype.unshift = Socket.prototype.unshift;
- AdbSocket.prototype.onPause = function() {};
- AdbSocket.prototype.onResume = function() {
- this.device.sendMessage(AdbDevice.kCommandOKAY, this.localId, this.remoteId)
- };
- function connectUsbAdb(handle, iface, cb) {
- console.log("connecting");
- var adb = new AdbDevice(new AdbUsbTransport(handle, iface), cb);
- console.log("sending CNXN");
- adb.sendMessage(AdbDevice.kCommandCNXN, AdbDevice.ADB_PROTOCOL_VERSION, AdbDevice.MAX_PAYLOAD, "host::");
- console.log("starting receive loop");
- adb.receiveMessages()
- }
- function AdbServer(options) {
- var options = options || {};
- var port = options.port || 5037;
- var start = options.start !== false;
- this.currentSocketId = 0;
- this.pendingDevices = {};
- this.port = port;
- this.adbDevices = {};
- this.clients = {};
- if (start) {
- this.start()
- }
- }
- function _nowMs() {
- return (new Date).getTime()
- }
- AdbServer.prototype.start = function() {
- if (this.server) {
- console.log("ADB Server started while already started");
- return
- }
- this.lastChange = _nowMs();
- this.clients = {};
- this.adbDevices = {};
- this.pendingDevices = {};
- this.refreshing = {};
- var server = new Server;
- server.listen({
- port: this.port,
- address: "127.0.0.1"
- }, function(socket) {
- var client = new AdbClient(this, socket);
- var socketId = ++this.currentSocketId;
- this.clients[socketId] = client;
- socket.onClose = function() {
- delete this.clients[socketId]
- }.bind(this);
- client.receiveHeader()
- }.bind(this), function(result) {
- if (result) {
- console.log("adb server failed to listen: " + result);
- return
- }
- console.log("ADB Server started");
- this.server = server;
- this.refresh()
- }.bind(this))
- };
- AdbServer.prototype.isRunning = function() {
- return this.server != null
- };
- AdbServer.prototype.kill = function() {
- this.lastChange = _nowMs();
- this.server.destroy();
- this.server = null;
- this.refreshing = {};
- for (var client in this.clients) {
- client = this.clients[client];
- client.socket.destroy()
- }
- this.clients = {};
- for (var device in this.adbDevices) {
- device = this.adbDevices[device];
- device.destroy()
- }
- this.adbDevices = {};
- this.pendingDevices = {}
- };
- AdbServer.prototype.selectDevice = function(cb) {
- chrome.usb.getUserSelectedDevices({
- filters: [{
- interfaceClass: 255,
- interfaceSubclass: 66,
- interfaceProtocol: 1
- }]
- }, function(devices) {
- for (var device in devices) {
- device = devices[device];
- this.refreshDevice(device, cb)
- }
- }.bind(this))
- };
- AdbServer.prototype.withAdbDevice = function(adb, cb) {
- adb.onError = function() {
- this.lastChange = _nowMs();
- delete this.adbDevices[adb.serialno]
- }.bind(this);
- var withSerial = function(str) {
- this.lastChange = _nowMs();
- adb.serialno = str.trim();
- this.adbDevices[adb.serialno] = adb;
- console.log("found device: " + adb.serialno);
- cb(adb)
- }.bind(this);
- if (adb.serialno) {
- withSerial(adb.serialno);
- return
- }
- adb.newSocket("shell:getprop ro.serialno", function(adbSocket) {
- readString(adbSocket, function(str) {
- withSerial(str)
- }.bind(this))
- }.bind(this))
- };
- AdbServer.prototype.tryDevice = function(handle, cb) {
- var adbDevices = this.adbDevices;
- var pending = this.pendingDevices;
- var server = this;
- function tryInterface(i) {
- var number = i.interfaceNumber;
- for (var existing in adbDevices) {
- existing = adbDevices[existing];
- if (existing.transport.iface && existing.transport.handle && existing.transport.iface.interfaceNumber == number && existing.transport.handle.productId == handle.productId && existing.transport.handle.vendorId == handle.vendorId) {
- return false
- }
- }
- if (pending[number]) {
- return false
- }
- pending[number] = handle;
- console.log("claiming:", JSON.stringify(handle), JSON.stringify(i));
- chrome.usb.claimInterface(handle, i.interfaceNumber, function() {
- console.log("claimed:", JSON.stringify(chrome.runtime.lastError));
- connectUsbAdb(handle, i, function(adb) {
- if (!adb) {
- delete pending[number];
- cb();
- return
- }
- server.withAdbDevice(adb, function(adb) {
- delete pending[number];
- cb(adb)
- })
- })
- });
- return true
- }
- chrome.usb.listInterfaces(handle, unsafeCallback(function(interfaces) {
- if (!interfaces) {
- console.log("unable list interfaces", JSON.stringify(chrome.runtime.lastError));
- if (cb) cb();
- return
- }
- console.log("got interfaces", JSON.stringify(interfaces));
- var usedHandle = false;
- for (var i in interfaces) {
- i = interfaces[i];
- if (i.interfaceClass == 255 && i.interfaceSubclass == 66 && i.interfaceProtocol == 1) {
- usedHandle |= tryInterface(i)
- }
- }
- if (!usedHandle) {
- chrome.usb.closeDevice(handle)
- }
- }))
- };
- AdbServer.prototype.refreshDevice = function(device, cb) {
- chrome.usb.openDevice(device, function(connectionHandle) {
- if (!connectionHandle) {
- console.log("unable to open device", JSON.stringify(chrome.runtime.lastError));
- if (cb) cb();
- return
- }
- this.start();
- this.tryDevice(connectionHandle, function(adb) {
- if (adb) {
- adb.usbDevice = device
- }
- cb(adb)
- })
- }.bind(this))
- };
- AdbServer.prototype.refresh = function() {
- if (!this.server) {
- console.log("adb server refresh requested while server killed");
- return
- }
- var now = _nowMs();
- if (this.server.lastRefresh && this.server.lastRefresh > now - 1e4) {
- return
- }
- this.server.lastRefresh = now;
- var vidpids = chrome.runtime.getManifest().permissions.pop().usbDevices;
- $(vidpids).each(function(index, vidpid) {
- var key = vidpid.vendorId + "&" + vidpid.productId;
- if (this.refreshing[key]) {
- return
- }
- this.refreshing[key] = true;
- chrome.usb.findDevices({
- productId: vidpid.productId,
- vendorId: vidpid.vendorId
- }, function(devices) {
- var waiting = devices.length;
- if (!waiting) {
- delete this.refreshing[key];
- return
- }
- console.log("found:", vidpid, devices);
- for (var device in devices) {
- console.log("trying:", devices[device]);
- this.tryDevice(devices[device], function() {
- waiting--;
- if (!waiting) {
- delete this.refreshing[key]
- }
- }.bind(this))
- }
- }.bind(this))
- }.bind(this));
- var now = _nowMs();
- for (var client in this.clients) {
- client = this.clients[client];
- if (client.tracking && now != client.tracking) {
- client.tracking = now;
- client.writeDevices({
- filter: client.tracked
- })
- }
- }
- };
- AdbServer.prototype.stop = function() {
- this.server.destroy()
- };
- function AdbClient(server, socket) {
- this.server = server;
- this.socket = socket
- }
- AdbClient.prototype.resolveTransport = function(transport, serialno) {
- if (serialno) {
- var ret = this.server.adbDevices[serialno];
- if (!ret) return "device not found";
- return ret
- }
- var num = Object.keys(this.server.adbDevices);
- if (num > 1) {
- return "more than one device"
- }
- if (num == 0) {
- return "no devices connected"
- }
- for (var device in this.server.adbDevices) {
- return this.server.adbDevices[device]
- }
- };
- AdbClient.prototype.write = function(data, status) {
- if (!status) {
- status = "OKAY"
- }
- data = str2ab(data);
- var len = data.byteLength;
- var len16 = make4Len16(len);
- len16 = str2ab(status + len16);
- var payload = appendBuffer(new Uint8Array(len16), new Uint8Array(data)).buffer;
- this.socket.write(payload, function() {})
- };
- AdbClient.prototype.writeDevices = function(options) {
- var options = options || {};
- var longformDevices = options.longformDevices;
- var filter = options.filter || null;
- var devices = "";
- for (var device in this.server.adbDevices) {
- if (filter && filter[device]) continue;
- device = this.server.adbDevices[device];
- devices += device.serialno + " device";
- if (longformDevices) {
- if (device.transport.constructor.name == "AdbUsbTransport") devices += " usb:" + device.transport.iface.interfaceNumber;
- else devices += " tpcip:" + "something";
- devices += " product:" + device.properties["ro.product.name"];
- devices += " model:" + device.properties["ro.product.model"];
- devices += " device:" + device.properties["ro.product.device"]
- }
- devices += "\n"
- }
- if (filter != null && devices.length == 0) return;
- this.write(devices)
- };
- AdbClient.prototype.handlePayload = function(data) {
- data = ab2str(data);
- var commandParts = data.split(":");
- var hostCmd = data;
- var serialno;
- if (commandParts[0] == "host-serial") {
- commandParts[0] = "host";
- serialno = commandParts.splice(1, 1)[0];
- if (Number.isInteger(parseInt(commandParts[1]))) {
- serialno += ":" + commandParts.splice(1, 1)[0]
- }
- }
- if (commandParts.length >= 2) hostCmd = commandParts[0] + ":" + commandParts[1];
- switch (hostCmd) {
- case "host:version":
- this.write(make4Len16(AdbDevice.ADB_VERSION));
- break;
- case "host:devices-l":
- case "host:devices":
- var longformDevices = data == "host:devices-l";
- this.server.refresh();
- this.writeDevices({
- longformDevices: longformDevices
- });
- break;
- case "host:transport-usb":
- case "host:transport-any":
- var transport = this.resolveTransport(data, serialno);
- if (transport.constructor.name == "String") {
- this.write(transport, "FAIL");
- break
- }
- this.transport = transport;
- this.socket.write(str2ab("OKAY"), function() {});
- break;
- case "host:kill":
- this.server.kill();
- break;
- case "host:connect":
- if (commandParts.length < 3) {
- this.write("need more arguments for connect <host>[:<port>]", "FAIL");
- break
- }
- var remoteHost = commandParts[2];
- var remotePort = 5555;
- if (commandParts.length > 3) remotePort = Number.parseInt(commandParts[3]);
- Socket.connect({
- host: remoteHost,
- port: remotePort
- }, function(socket) {
- if (!socket) {
- this.write("connecting " + remoteHost + " " + remotePort, "FAIL");
- return this
- }
- var adb = new AdbDevice(new AdbTcpTransport(socket), function(adb) {
- this.server.withAdbDevice(adb, function() {
- console.log("connected?");
- this.socket.write(str2ab("OKAYOKAY"), function() {})
- }.bind(this))
- }.bind(this));
- adb.serialno = remoteHost + ":" + remotePort;
- socket.onClose = function() {
- adb.fatal("socket closed")
- }.bind(this);
- adb.sendMessage(AdbDevice.kCommandCNXN, AdbDevice.ADB_PROTOCOL_VERSION, AdbDevice.MAX_PAYLOAD, "host::");
- adb.receiveMessages()
- }.bind(this));
- break;
- case "host:track-devices":
- this.tracking = _nowMs();
- this.writeDevices();
- this.tracked = Object.fromArray(Object.keys(this.server.adbDevices));
- break;
- case "host:forward":
- var forwardParts = commandParts.join(":").substring(hostCmd.length + 1).split(";");
- var from = forwardParts[0].split(":");
- var fromPort = parseInt(from[1]);
- var transport = this.resolveTransport(data, serialno);
- if (transport.constructor.name == "String") {
- this.write(transport, "FAIL");
- break
- }
- transport.forwardPort({
- fromPort: fromPort,
- to: forwardParts[1]
- });
- this.socket.write(str2ab("OKAYOKAY"), function() {}.bind(this));
- break;
- default:
- if (this.transport) {
- var transport = this.transport;
- transport.newSocket(data, function(socket) {
- this.socket.write(str2ab("OKAY"), function() {});
- Socket.stream(socket, this.socket)
- }.bind(this));
- return
- }
- var specific = "host:transport:";
- if (data.startsWith(specific)) {
- var serialno = data.substr(specific.length);
- var device = this.server.adbDevices[serialno];
- if (!device) {
- this.write("device not found", "FAIL");
- return
- }
- this.transport = device;
- this.socket.write(str2ab("OKAY"), function() {});
- break
- }
- console.log("unknown request: " + data);
- this.write("unknown command: " + data, "FAIL");
- var appName = chrome.runtime.getManifest().name;
- chrome.notifications.create({
- type: "basic",
- iconUrl: "/icon.png",
- title: appName,
- message: appName + "'s adb server encountered an unknown adb command.\nYou may want to close " + appName + " and start your adb binary manually."
- });
- break
- }
- this.receiveHeader()
- };
- AdbClient.prototype.receivePayload = function(data) {
- var len = parseInt(ab2str(data), 16);
- this.socket.read(len, this.handlePayload.bind(this))
- };
- AdbClient.prototype.receiveHeader = function() {
- this.socket.read(4, this.receivePayload.bind(this))
- };
- var Adb = {};
- Adb.sendHostCommand = function(command, cb) {
- Socket.connect({
- host: "127.0.0.1",
- port: 5037
- }, function(socket) {
- if (!socket) {
- cb();
- return
- }
- command = make4Len16(command.length) + command;
- socket.read(4, function(ok) {
- if (ab2str(ok) != "OKAY") {
- socket.destroy();
- cb();
- return
- }
- socket.read(4, function(len) {
- var lenStr = ab2str(len);
- len = parseInt(lenStr, 16);
- if (len == 0 || lenStr == "OKAY") {
- cb(socket, new ArrayBuffer(0));
- return
- }
- socket.read(len, function(data) {
- cb(socket, data)
- })
- })
- });
- socket.write(str2ab(command), function() {})
- })
- };
- Adb.devices = function(cb) {
- var adbDevices = {};
- function parseConnectionPayload(payload) {
- var rawPayload = payload;
- payload = payload.replace(" ", " ");
- var i = payload.indexOf(" ");
- if (i == -1) {
- cb({});
- return
- }
- var serialno = payload.substring(0, i);
- payload = payload.substring(i).trim();
- var newPayload;
- while (newPayload != payload) {
- newPayload = payload;
- payload = payload.replace(" ", " ")
- }
- var values = {};
- var firstSpace = payload.indexOf(" ");
- if (firstSpace == -1) return;
- var status = payload.substring(0, firstSpace);
- payload = payload.substring(firstSpace + 1);
- while (payload.length) {
- i = payload.indexOf(":");
- if (i == -1) break;
- var key = payload.substring(0, i);
- var rest = payload.substring(i + 1);
- var nextSpace = rest.indexOf(" ");
- var nextColon = rest.indexOf(":");
- var value;
- if (nextSpace == -1 || nextColon == -1) {
- value = rest;
- payload = ""
- } else {
- while (nextSpace != -1 && nextSpace < nextColon) {
- value = rest.substring(0, nextSpace);
- payload = rest.substring(nextSpace + 1);
- nextSpace = rest.indexOf(" ", nextSpace + 1)
- }
- }
- values[key] = value
- }
- var name;
- if (!values["model"]) name = serialno;
- else name = values["model"].replace("_", " ");
- adbDevices[serialno] = {
- name: name,
- status: status,
- properties: rawPayload
- }
- }
- Adb.sendHostCommand("host:devices-l", function(socket, data) {
- if (!socket) {
- cb();
- return
- }
- socket.destroy();
- data = ab2str(data);
- data = data.trim();
- var lines = data.split("\n");
- for (var line in lines) {
- line = lines[line];
- parseConnectionPayload(line)
- }
- cb(adbDevices)
- })
- };
- Adb.killServer = function(cb) {
- Adb.sendHostCommand("host:kill-server", function(socket, data) {
- if (!socket) {
- cb();
- return
- }
- socket.destroy();
- data = ab2str(data);
- if (cb) cb()
- })
- };
- Adb.sendClientCommand = function(options, cb) {
- var command = options.command;
- var serialno = options.serialno;
- Socket.connect({
- host: "127.0.0.1",
- port: 5037
- }, function(socket) {
- if (!socket) {
- cb();
- return
- }
- socket.read(4, function(data) {
- var result = ab2str(data);
- if (result != "OKAY") {
- socket.destroy();
- cb(null);
- return
- }
- var clientCommand = command;
- clientCommand = make4Len16(clientCommand.length) + clientCommand;
- socket.read(4, function(data) {
- var result = ab2str(data);
- if (result != "OKAY") {
- socket.destroy();
- cb(null);
- return
- }
- cb(socket)
- });
- socket.write(str2ab(clientCommand), function() {})
- });
- var hostCommand = "host:transport:" + serialno;
- hostCommand = make4Len16(hostCommand.length) + hostCommand;
- socket.write(str2ab(hostCommand), function() {})
- })
- };
- Adb.shell = function(options, cb) {
- var command = options.command;
- var serialno = options.serialno;
- Adb.sendClientCommand({
- serialno: serialno,
- command: "shell:" + command
- }, function(socket) {
- if (!socket) {
- cb();
- return
- }
- readString(socket, function(str) {
- cb(str)
- })
- })
- };
- Adb.forward = function(options, cb) {
- var command = "host-serial:" + options.serialno + ":forward:" + options.from + ";" + options.to;
- Adb.sendHostCommand(command, function(socket, err) {
- if (socket) socket.destroy();
- cb(socket, err)
- })
- };
- function AdbSync() {}
- AdbSync.MKID = function(a, b, c, d) {
- return a.charCodeAt(0) | b.charCodeAt(0) << 8 | c.charCodeAt(0) << 16 | d.charCodeAt(0) << 24
- };
- AdbSync.ID_RECV = AdbSync.MKID("R", "E", "C", "V");
- AdbSync.ID_SEND = AdbSync.MKID("S", "E", "N", "D");
- AdbSync.ID_DONE = AdbSync.MKID("D", "O", "N", "E");
- AdbSync.ID_DATA = AdbSync.MKID("D", "A", "T", "A");
- AdbSync.DATA_MAX = 64 * 1024;
- Adb.pull = function(options, cb) {
- var file = options.file;
- var serialno = options.serialno;
- var fileEntry = options.fileEntry;
- Adb.sendClientCommand({
- serialno: serialno,
- command: "sync:"
- }, function(socket) {
- if (!socket) {
- cb();
- return
- }
- fileEntry.createWriter(function(fileWriter) {
- var msg = new ArrayBuffer(8);
- var msgView = new DataView(msg);
- msgView.setUint32(0, AdbSync.ID_RECV, true);
- msgView.setUint32(4, file.length, true);
- socket.write(msg, function() {
- socket.write(str2ab(file), function() {
- function readChunk(len) {
- socket.read(len, function(data) {
- fileWriter.write(new Blob([data]))
- })
- }
- fileWriter.onwriteend = function(e) {
- readHeader()
- };
- function readHeader() {
- socket.read(8, function(data) {
- var view = new DataView(data.buffer, data.byteOffset, data.byteLength);
- var id = view.getUint32(0, true);
- if (id == AdbSync.ID_DATA) {
- var len = view.getUint32(4, true);
- readChunk(len);
- return
- }
- socket.destroy();
- if (id == AdbSync.ID_DONE) {
- cb(fileEntry);
- return
- }
- cb()
- })
- }
- readHeader()
- })
- })
- })
- })
- };
- Adb.push = function(options, cb) {
- var file = options.file;
- var serialno = options.serialno;
- var fileSocket = options.socket;
- Adb.sendClientCommand({
- serialno: serialno,
- command: "sync:"
- }, function(socket) {
- if (!socket) {
- cb();
- return
- }
- var msg = new ArrayBuffer(8);
- var msgView = new DataView(msg);
- var fileAndMode = file + ",0644";
- msgView.setUint32(0, AdbSync.ID_SEND, true);
- msgView.setUint32(4, fileAndMode.length, true);
- socket.write(msg, function() {
- socket.write(str2ab(fileAndMode), function() {
- var done;
- var writing = true;
- fileSocket.onClose = function() {
- var msg = new ArrayBuffer(8);
- var msgView = new DataView(msg);
- msgView.setUint32(0, AdbSync.ID_DONE, true);
- msgView.setUint32(4, 0, true);
- socket.write(msg, function() {
- socket.read(8, function() {
- cb()
- })
- })
- };
- function readChunk() {
- fileSocket.read(function(data) {
- if (data.byteLength > AdbSync.DATA_MAX) {
- var extra = data.subarray(AdbSync.DATA_MAX);
- data = data.subarray(0, AdbSync.DATA_MAX);
- fileSocket.unshift(extra)
- }
- writeChunk(data)
- })
- }
- function writeChunk(data) {
- var msg = new ArrayBuffer(8);
- var msgView = new DataView(msg);
- msgView.setUint32(0, AdbSync.ID_DATA, true);
- msgView.setUint32(4, data.byteLength, true);
- socket.write(msg, function() {
- var buffer = data.buffer;
- if (data.byteOffset || data.length != buffer.byteLength) {
- buffer = buffer.slice(data.byteOffset, data.byteOffset + data.byteLength)
- }
- socket.write(buffer, function() {
- readChunk()
- })
- })
- }
- readChunk()
- })
- })
- })
- };
- function AdbDaemon(transport, maxPayload) {
- this.transport = transport;
- this.sockets = {};
- this.currentSocketId = 0;
- this.maxPayload = maxPayload || AdbDevice.MAX_PAYLOAD
- }
- AdbDaemon.prototype.start = function(properties) {
- var props = str2ab(properties, undefined, true);
- this.sendMessage(AdbDevice.kCommandCNXN, AdbDevice.ADB_PROTOCOL_VERSION, this.maxPayload, props);
- this.receiveMessages()
- };
- AdbDaemon.prototype.fatal = function(result) {
- console.log("fatal error", result)
- };
- AdbDaemon.prototype.sendMessage = AdbDevice.prototype.sendMessage;
- AdbDaemon.prototype.receiveMessages = AdbDevice.prototype.receiveMessages;
- AdbDaemon.prototype.handleUnknown = AdbDevice.prototype.handleUnknown;
- AdbDaemon.prototype.newAdbSocket = AdbDevice.prototype.newAdbSocket;
- AdbDaemon.prototype.destroy = AdbDevice.prototype.destroy;
- AdbDaemon.prototype.onOpenSocket = function(payload, remoteSocketId) {
- if (this.openSocket) {
- var socketId = ++this.currentSocketId;
- var socket = this.newAdbSocket(socketId);
- socket.remoteId = remoteSocketId;
- this.sockets[socketId] = socket;
- this.sendMessage(AdbDevice.kCommandOKAY, socketId, remoteSocketId);
- this.openSocket(ab2str(payload), socket)
- }
- };
- function LicenseManager() {
- this.licensed = false;
- this.licenseCached = false
- }
- LicenseManager.prototype.refresh = function(cb) {
- var doCallback = function() {
- if (cb) cb();
- if (this.globalRefresh) this.globalRefresh()
- }.bind(this);
- var checkPayments = function(payments) {
- $.each(payments, function(index, detail) {
- console.log("subscription status", detail.sku, detail.state);
- if (detail.state == "ACTIVE") this.licensed = true
- }.bind(this))
- }.bind(this);
- var checkServer = function() {
- google.payments.inapp.getPurchases({
- parameters: {
- env: "prod"
- },
- success: function(response) {
- checkPayments(response.response.details);
- if (this.isLicensed()) {
- var pw = chrome.app.window.get("purchase");
- if (pw != null) {
- pw.close();
- showNotification("Vysor subscription is active. Thank you for your support!")
- }
- this.cacheLicense(function() {
- if (this.isLicenseCached() && this.globalRefresh) this.globalRefresh()
- }.bind(this), {
- interactive: false
- })
- }
- doCallback()
- }.bind(this),
- failure: function() {
- console.log("failed to refresh license", arguments);
- doCallback()
- }.bind(this)
- })
- }.bind(this);
- chrome.storage.local.get("cachedLicense", function(d) {
- if (!d.cachedLicense) {
- checkServer();
- return
- }
- var signature = base64ToArrayBuffer(d.cachedLicense.signature);
- var signedData = str2ab(d.cachedLicense.signed_data);
- window.crypto.subtle.importKey("jwk", {
- kty: "RSA",
- e: "AQAB",
- n: "vMGBBmLcMO4lOmg-YAHq2DjZKHTaW-xs9KPNXU_zKJ7ZhFhWH3I6skF9ZO8lKeXOSwVEIW4HVMa7m16S6WTrUw",
- alg: "RS1"
- }, {
- name: "RSASSA-PKCS1-v1_5",
- hash: {
- name: "SHA-1"
- }
- }, true, ["verify"]).then(function(publicKey) {
- window.crypto.subtle.verify({
- name: "RSASSA-PKCS1-v1_5",
- hash: {
- name: "SHA-1"
- }
- }, publicKey, signature, signedData).then(function(isvalid) {
- if (!isvalid) {
- console.error("invalid signature");
- checkServer();
- return
- }
- var data = JSON.parse(d.cachedLicense.signed_data);
- if (data.date > Date.now()) {
- console.log("cached license date from future?");
- checkServer();
- return
- }
- if (data.date + 24 * 60 * 60 * 1e3 < Date.now()) {
- console.log("cached license is expired.");
- checkServer();
- return
- }
- chrome.identity.getProfileUserInfo(function(userInfo) {
- if (!userInfo) {
- console.log("unable to retrieve user info");
- checkServer();
- return
- }
- if (userInfo.id != data.userinfo.id) {
- console.log("id mismatch");
- checkServer();
- return
- }
- checkPayments(data.payments);
- if (!this.isLicensed()) {
- checkServer();
- return
- }
- console.log("cached license is valid for " + (data.date + 24 * 60 * 60 * 1e3 - Date.now()) / (60 * 60 * 1e3) + " hours");
- this.licenseCached = true;
- doCallback()
- }.bind(this))
- }.bind(this)).catch(function(err) {
- console.error("cached license check failed", err);
- checkServer()
- })
- }.bind(this)).catch(function(err) {
- console.error("key import failed", err);
- checkServer()
- })
- }.bind(this))
- };
- LicenseManager.prototype.cacheLicense = function(cb, opts) {
- if (!opts) {
- opts = {
- interactive: true
- }
- }
- chrome.identity.getAuthToken(opts, function(token) {
- if (!token) {
- showNotification("Unable to get auth token.");
- return
- }
- $.ajax({
- type: "post",
- url: "https://clockworkbilling.appspot.com/api/v1/verify/google/koushd@gmail.com",
- data: {
- token: token,
- item: chrome.runtime.id
- },
- dataType: "json",
- success: function(data) {
- this.licenseCached = true;
- chrome.storage.local.set({
- cachedLicense: data
- }, cb)
- }.bind(this),
- error: function(xhr, e) {
- if (cb) cb(e)
- }
- })
- }.bind(this))
- };
- LicenseManager.prototype.isLicensed = function() {
- return this.licensed
- };
- LicenseManager.prototype.isLicenseCached = function() {
- return this.licenseCached
- };
- LicenseManager.prototype.startPurchase = function() {
- chrome.app.window.create("purchase.html", {
- id: "purchase",
- resizable: false,
- bounds: {
- width: 800,
- height: 800
- }
- }, function(w) {
- this.refresh();
- w.contentWindow.refreshLicenseManager = function() {
- this.refresh()
- }.bind(this)
- }.bind(this))
- };
- (function() {
- var adbServer = new AdbServer({
- start: false
- });
- var vysorVirtualDevices = {};
- var shells = {};
- var list;
- var shareAdbMaxPayload = 512 * 1024;
- var analyticsService = analytics.getService("vysor_app");
- var tracker = analyticsService.getTracker("UA-4956323-6");
- var licenseManager = new LicenseManager;
- licenseManager.globalRefresh = function() {
- refreshListBitrate();
- refreshListWithLicense()
- };
- licenseManager.refresh();
- function refreshListWithLicense() {
- if (!licenseManager.isLicensed() || !list) return;
- $(list.contentWindow.document).find("#purchase").hide();
- if (licenseManager.isLicenseCached()) $(list.contentWindow.document).find("#login-container").hide();
- else $(list.contentWindow.document).find("#login-container").show()
- }
- var h264Acceleration = "software";
- function refreshListBitrate() {
- if (!licenseManager.isLicensed()) return;
- if (!list) return;
- chrome.storage.local.get("bitrate", function(d) {
- $(list.contentWindow.document).find("#bitrate")[0].selectedIndex = d.bitrate
- })
- }
- function libind(feature, f, fb) {
- return function() {
- if (!licenseManager.isLicensed()) {
- showNotification("The " + feature + " feature is only avaiable to Vysor Pro users.");
- licenseManager.startPurchase();
- if (fb) fb.apply(this, arguments);
- return
- }
- f.apply(this, arguments)
- }
- }
- function licheck(feature, f) {
- if (!licenseManager.isLicensed()) {
- showNotification("The " + feature + " feature is only avaiable to Vysor Pro users.");
- licenseManager.startPurchase();
- return
- }
- f()
- }
- var vysorForceSocket;
- chrome.storage.local.get("vysorForceSocket", function(d) {
- vysorForceSocket = d.vysorForceSocket
- });
- function updateWindowStatusText(serialno, text) {
- var existing = chrome.app.window.get(serialno);
- if (!existing) return;
- $(existing.contentWindow.document).find("#loading-text").html(text)
- }
- function installApk(serialno, cb) {
- updateWindowStatusText(serialno, "Installing Vysor APK...");
- $.ajax({
- url: "/Vysor-release.apk",
- dataType: "binary",
- responseType: "arraybuffer",
- success: function(ab) {
- var uib = new Uint8Array(ab);
- var dummy = new DummySocket(uib);
- var tmp = "/data/local/tmp/vysor" + (new Date).getTime() + ".apk";
- Adb.push({
- serialno: serialno,
- file: tmp,
- socket: dummy
- }, function() {
- Adb.shell({
- command: "pm install -r " + tmp,
- serialno: serialno
- }, cb)
- })
- }
- })
- }
- function startMirrorServer(serialno, port, cb) {
- updateWindowStatusText(serialno, "Connecting...");
- function runWithPath(path) {
- var password = Math.round(Math.random() * (1 << 30)).toString(16);
- var pwcmd = "echo -n " + password + " > /data/local/tmp/vysor.pwd ; chmod 600 /data/local/tmp/vysor.pwd";
- Adb.shell({
- command: "ls -l /system/bin/app_process*",
- serialno: serialno
- }, function(test) {
- var appProcess = "/system/bin/app_process";
- if (test && test.indexOf("app_process32") != -1) {
- appProcess += "32"
- }
- Adb.sendClientCommand({
- command: 'shell:sh -c "CLASSPATH=' + path + " " + appProcess + " /system/bin com.koushikdutta.vysor.Main " + password + '"',
- serialno: serialno
- }, function(socket) {
- Adb.shell({
- serialno: serialno,
- command: 'sh -c "' + pwcmd + '"'
- }, function(ignored) {
- Socket.eat(socket);
- cb(port, password)
- })
- })
- })
- }
- function tryGetPath(cb) {
- updateWindowStatusText(serialno, "Connecting...");
- Adb.shell({
- command: "pm path com.koushikdutta.vysor",
- serialno: serialno
- }, function(path) {
- if (path == "" || !path) {
- cb(null);
- return
- }
- var match = path.match(/package:\/.*?[\r\n]/);
- if (!match || !match.length) {
- cb(null);
- return
- }
- path = match[0];
- path = path.replace("package:", "").trim();
- Adb.shell({
- command: 'sh -c "CLASSPATH=' + path + ' /system/bin/app_process /system/bin com.koushikdutta.vysor.ProtocolVersionMain"',
- serialno: serialno
- }, function(version) {
- var match = version.match(/vysor-io-.*?[\r\n]/);
- if (!match || !match.length) {
- cb(null);
- return
- }
- version = match[0];
- if (version) version = version.trim();
- console.log("protocol version: " + version);
- if (version != "vysor-io-18") cb(null);
- else cb(path)
- })
- })
- }
- tryGetPath(function(path) {
- if (!path) {
- console.log("installing apk");
- installApk(serialno, function(result) {
- tryGetPath(function(path) {
- if (!path) {
- console.log("wtf apk install failed? " + result);
- showNotification("Error installing APK:\n" + result.trim());
- closeWindow(serialno);
- return
- }
- runWithPath(path)
- })
- });
- return
- }
- runWithPath(path)
- })
- }
- function closeWindow(serialno) {
- var existing = chrome.app.window.get(serialno);
- if (existing) existing.close()
- }
- var portCount = 53516;
- function forwardPort(serialno, cb) {
- var port = portCount++;
- Adb.forward({
- from: "tcp:" + port,
- to: "tcp:53516",
- serialno: serialno
- }, function() {
- startMirrorServer(serialno, port, cb)
- })
- }
- function withWindow(w, serialno, port, password) {
- w.contentWindow.adbServer = adbServer;
- w.contentWindow.Adb = Adb;
- w.contentWindow.port = port;
- w.contentWindow.password = password;
- w.contentWindow.serialno = serialno;
- w.contentWindow.tracker = tracker;
- w.contentWindow.vysorVirtualDevices = vysorVirtualDevices;
- w.contentWindow.vysorForceSocket = vysorForceSocket;
- w.contentWindow.acceleration = h264Acceleration;
- w.contentWindow.Function.prototype.libind = function(feature, t) {
- return function() {
- if (!licenseManager.isLicensed()) {
- showNotification("The " + feature + " is only avaiable to Vysor Pro users.");
- licenseManager.startPurchase();
- return
- }
- this.apply(t, arguments)
- }.bind(this)
- };
- if (!w.contentWindow.hasDocReadied) {
- $(w.contentWindow.document).ready(function() {
- w.contentWindow.hasDocReadied = true;
- w.contentWindow.docReady();
- w.contentWindow.connectionReady()
- })
- } else {
- w.contentWindow.connectionReady()
- }
- }
- function maybeClose() {
- setTimeout(function() {
- if (!chrome.app.window.getAll().length) {
- chrome.runtime.reload()
- }
- }, 5e3)
- }
- function openWindow(serialno, reconnect) {
- checkForUpdates();
- var existing = chrome.app.window.get(serialno);
- if (existing) {
- existing.show();
- if (reconnect) {
- forwardPort(serialno, function(port, password) {
- withWindow(existing, serialno, port, password)
- })
- }
- return
- }
- chrome.app.window.create("screen.html", {
- id: serialno,
- bounds: {
- width: 405,
- height: 720
- }
- }, function(w) {
- forwardPort(serialno, function(port, password) {
- withWindow(w, serialno, port, password);
- Adb.shell({
- command: "am start com.koushikdutta.vysor/.TipsActivity",
- serialno: serialno
- }, function() {})
- });
- w.onClosed.addListener(function() {
- maybeClose();
- if (w.contentWindow.h264Socket) {
- console.log("cleaning up h264 socket");
- w.contentWindow.h264Socket.destroy()
- }
- })
- })
- }
- function updateBitrates(index) {
- var bitrates = [5e5, 75e4, 1e6, 15e5, 2e6];
- var bitrate = bitrates[index];
- var windows = chrome.app.window.getAll();
- for (var w in windows) {
- w = windows[w];
- if (!w.contentWindow.serialno) continue;
- w.contentWindow.sendEvent({
- type: "bitrate",
- bitrate: bitrate
- })
- }
- }
- function openList(cb) {
- if (list) {
- if (cb) {
- cb(list)
- }
- return
- }
- chrome.app.window.create("list.html", {
- id: "list",
- bounds: {
- width: 480,
- height: 480
- }
- }, function(w) {
- list = w;
- list.contentWindow.appcallback = function() {
- refreshListBitrate();
- if (navigator.platform.toLowerCase().indexOf("win") == -1) {
- $(list.contentWindow.document).find("#windows").hide()
- }
- list.contentWindow.adbServer = adbServer;
- list.contentWindow.tracker = tracker;
- chrome.storage.local.get("connect-automatically", function(vals) {
- var connectAuto = vals["connect-automatically"] !== false;
- $(list.contentWindow.document).find("#connect-automatically-check").prop("checked", connectAuto)
- });
- $(list.contentWindow.document).find("#bitrate").change(libind("Image Quality", function() {
- updateBitrates(this.selectedIndex);
- chrome.storage.local.set({
- bitrate: this.selectedIndex
- })
- }, function() {
- this.selectedIndex = 0
- }));
- $(list.contentWindow.document).find("#connect-automatically-check").change(function() {
- chrome.storage.local.set({
- "connect-automatically": this.checked
- })
- });
- $(list.contentWindow.document).find("#connect-android").hide();
- $(list.contentWindow.document).find("#purchase").click(function() {
- licenseManager.startPurchase()
- });
- $(list.contentWindow.document).find("#login").click(function() {
- $(list.contentWindow.document).find("#login-line").hide();
- $(list.contentWindow.document).find("#logging-in").show();
- licenseManager.cacheLicense(function(e) {
- if (e) {
- showNotification("Error saving license for offline use: " + e);
- $(list.contentWindow.document).find("#login-line").show();
- $(list.contentWindow.document).find("#logging-in").hide();
- return
- }
- $(list.contentWindow.document).find("#logging-in").hide();
- showNotification("License was saved for offline use. Thanks!")
- })
- });
- refreshListWithLicense()
- };
- list.onClosed.addListener(function() {
- list = null;
- maybeClose()
- });
- if (cb) {
- controller = new Controller(receiverWindow.contentWindow, true);
- cb(receiverWindow)
- }
- })
- }
- function connectSharedDevice(url) {
- showNotification("Vysor is connecting to a remote Android device");
- if (list) list.show();
- console.log("attempting to connect to shared device", url);
- if (!gcmSocketManager) {
- console.log("gcm not ready.");
- return
- }
- adbServer.start();
- var registrationId;
- var channel;
- var u = new URL(url);
- if (!(registrationId = getQueryVariable("registrationId", u)) || !(channel = getQueryVariable("channel", u))) {
- var splits = u.pathname.split("/");
- registrationId = splits[2];
- channel = splits[3]
- }
- var server = new Server;
- server.listen({
- port: 0,
- address: "127.0.0.1"
- }, function(socket) {
- var daemon = new AdbDaemon(new AdbTcpTransport(socket));
- gcmSocketManager.connect(registrationId, channel, function(gcmConn) {
- tracker.sendEvent("connected-shared-device");
- var serialno = "127.0.0.1:" + server.localPort;
- vysorVirtualDevices[serialno] = gcmConn;
- console.log("connected gcm socket");
- gcmConn.openSocket = function() {
- console.log("got a new socket? this should not happen...");
- gcmConn.destroy()
- };
- daemon.openSocket = function(command, adbSocket) {
- gcmConn.newSocket(command, function(repeaterSocket) {
- Socket.stream(adbSocket, repeaterSocket, function() {})
- })
- };
- gcmConn.onClose = function() {
- daemon.destroy()
- };
- gcmConn.newSocket("properties", function(gcmSocket) {
- readString(gcmSocket, function(properties) {
- daemon.start(properties);
- console.log("got properties", properties)
- })
- })
- })
- }.bind(this), function(result) {
- if (result) {
- console.log("adb daemon failed to listen: " + result);
- return
- }
- Adb.sendHostCommand("host:connect:127.0.0.1:" + server.localPort, function(socket, data) {
- if (!socket) {
- return
- }
- socket.destroy();
- data = ab2str(data);
- console.log(data)
- })
- }.bind(this))
- }
- chrome.app.runtime.onLaunched.addListener(function(e) {
- openList();
- if (e && e.id == "vysor_presentation") {
- connectSharedDevice(e.url);
- return
- }
- checkForUpdates()
- });
- function checkForUpdates() {
- chrome.runtime.requestUpdateCheck(function(status, details) {
- if (status == "update_available") {
- notifyUpdateAvailable()
- }
- })
- }
- var gcmSocketManager;
- GcmRtcManager.start("64148182473", "AIzaSyDd7k1v017osyYbIC92fyf-36s3pv0z73U", {
- iceServers: [{
- url: "turn:n0.clockworkmod.com",
- username: "foo",
- credential: "bar"
- }, {
- url: "turn:n1.clockworkmod.com",
- username: "foo",
- credential: "bar"
- }]
- }, function(gcm) {
- gcmSocketManager = gcm;
- gcmSocketManager.sharedDevices = {}
- });
- function shareDevice(serialno, device) {
- var sharekey = Math.round(Math.random() * (1 << 30)).toString(16);
- gcmSocketManager.sharedDevices[serialno] = sharekey;
- var url = "https://vysor.clockworkmod.com/redirect/" + encodeURIComponent(gcmSocketManager.registrationId) + "/" + sharekey;
- url = "https://vysor.clockworkmod.com/app/vysor?registrationId=" + encodeURIComponent(gcmSocketManager.registrationId) + "&channel=" + sharekey;
- console.log(url);
- var properties = device.properties.substring(device.properties.indexOf("product")).replace(/ /g, ";").replace("device", "ro.product.device").replace("model", "ro.product.model").replace("product", "ro.product.name").replace(/:/g, "=");
- properties = "device::" + properties + ";";
- gcmSocketManager.listen(sharekey, function(gcmConn) {
- tracker.sendEvent("shared-device");
- if (!gcmSocketManager.sharedDevices[serialno]) {
- gcmConn.destroy();
- console.log("device is no longer being shared.");
- return
- }
- console.log("accepted gcm socket");
- Adb.sendClientCommand({
- serialno: serialno,
- command: "shell:"
- }, function(shellSocket) {
- shellSocket.onClose = function() {
- gcmConn.destroy()
- };
- function reader() {
- shellSocket.read(reader)
- }
- reader()
- });
- gcmConn.openSocket = function(command, adbSocket) {
- if (command == "properties") {
- adbSocket.write(str2ab(properties), function() {
- console.log("sent properties", properties);
- adbSocket.destroy()
- });
- return
- }
- if (command == "webstart") {
- startMirrorServer(serialno, null, function(port, password) {
- writeLine(adbSocket, password, function() {
- console.log("sent password", password);
- adbSocket.destroy()
- });
- Adb.shell({
- command: "am start com.koushikdutta.vysor/.TipsActivity",
- serialno: serialno
- }, function() {})
- });
- return
- }
- Adb.sendClientCommand({
- serialno: serialno,
- command: command
- }, function(socket) {
- if (!socket) {
- console.log("unable to execute adb proxy command?", command);
- adbSocket.destroy();
- return
- }
- Socket.stream(socket, adbSocket, function() {})
- })
- }
- });
- copyTextToClipboard(url);
- var appName = chrome.runtime.getManifest().name;
- showNotification("Copied " + appName + " share URL to clipboard.");
- chrome.browser.openTab({
- url: "http://www.vysor.io/share#" + url
- })
- }
- var adbDevices = {};
- var hadAdbServer;
- function refreshList() {
- if (!list) {
- return
- }
- $(list.contentWindow.document).find("#devices").empty();
- var keys = Object.keys(adbDevices);
- if (!keys.length) {
- var ele = $('<li><a href="#">No devices found</li>');
- if (!hadAdbServer || adbServer.isRunning()) {
- $(list.contentWindow.document).find("#choose-header").hide();
- ele.hide()
- }
- $(list.contentWindow.document).find("#devices").append(ele)
- } else {
- $(list.contentWindow.document).find("#choose-header").show();
- $(keys).each(function(index, serialno) {
- var d = adbDevices[serialno];
- var device = d.name;
- var display = device + " - " + serialno;
- if (d.status == "unauthorized") display = serialno + " - unauthorized";
- var ele = $('<li class="list-group-item"><span class="share badge">Share</span>' + display + "</li>");
- $(list.contentWindow.document).find("#devices").append(ele);
- var share = ele.find(".share");
- if (!gcmSocketManager || vysorVirtualDevices[serialno]) share.hide();
- ele.click(function() {
- if (d.status == "unauthorized") {
- showNotification('Check your Android device and click "Allow USB Debugging".')
- } else {
- tracker.sendEvent("click-device", device);
- openWindow(serialno)
- }
- });
- share.click(libind("Vysor Share", function(e) {
- e.stopPropagation();
- shareDevice(serialno, d)
- }, function(e) {
- e.stopPropagation()
- }))
- })
- }
- }
- var hasRefreshedOnce;
- function initRefresher() {
- chrome.storage.local.get("connect-automatically", function(vals) {
- var connectAuto = vals["connect-automatically"] !== false;
- Adb.devices(function(devices) {
- if (devices) {
- hadAdbServer = true;
- var newDevices = [];
- var hasDevices;
- $.each(devices, function(serialno, adb) {
- hasDevices = true;
- if (!adbDevices[serialno]) {
- tracker.sendEvent("found-device", adb.name);
- if (gcmSocketManager) {
- delete gcmSocketManager.sharedDevices[serialno]
- }
- var device = devices[serialno];
- var isEmulator = device.properties.indexOf("emulator") != -1 || device.properties.indexOf("vbox") != -1;
- if (!isEmulator && hasRefreshedOnce) {
- if (connectAuto || chrome.app.window.get(serialno) || adbServer.isRunning()) {
- openWindow(serialno, true);
- if (!list && !chrome.app.window.get(serialno)) {
- var appName = chrome.runtime.getManifest().name;
- chrome.notifications.create("never-start-automatically", {
- type: "basic",
- iconUrl: "/icon.png",
- title: appName,
- message: "Vysor has connected to an Android device and is starting.",
- buttons: [{
- title: "Never Start Automatically"
- }]
- })
- }
- }
- }
- }
- });
- adbDevices = devices;
- if (list) {
- if (hasDevices) $(list.contentWindow.document).find("#not-found").hide();
- else $(list.contentWindow.document).find("#not-found").show()
- }
- } else {
- hadAdbServer = false;
- adbDevices = {}
- }
- hasRefreshedOnce = true
- })
- })
- }
- initRefresher();
- var adbPort;
- function startAdbPort() {
- if (adbPort) return;
- adbPort = chrome.runtime.connectNative("com.clockworkmod.adb");
- adbPort.onDisconnect.addListener(function() {
- adbPort = null
- });
- adbPort.postMessage({
- command: "start-server"
- })
- }
- function refreshDevices() {
- if (list) {
- if (!hadAdbServer || adbServer.isRunning()) {
- $(list.contentWindow.document).find("#connect-android").show();
- $(list.contentWindow.document).find("#no-devices").hide()
- } else {
- $(list.contentWindow.document).find("#connect-android").hide();
- $(list.contentWindow.document).find("#no-devices").show()
- }
- if (!hadAdbServer) {
- if (navigator.userAgent.indexOf("Windows NT 10") != -1 && adbPort == null) {
- $(list.contentWindow.document).find("#adb-server-status").show();
- $(list.contentWindow.document).find("#adb-server-status").html("Windows 10 users MUST download the latest <a href='http://koush.com/post/universal-adb-driver' target='_blank'> Universal ADB Drivers</a>")
- } else {
- $(list.contentWindow.document).find("#adb-server-status").hide()
- }
- startAdbPort()
- } else {
- $(list.contentWindow.document).find("#adb-server-status").show();
- if (adbServer.isRunning()) {
- $(list.contentWindow.document).find("#adb-server-status").text("Vysor ADB Server started.")
- } else {
- $(list.contentWindow.document).find("#adb-server-status").text("ADB Server binary started.")
- }
- }
- }
- initRefresher();
- refreshList();
- setTimeout(refreshDevices, 1e3)
- }
- refreshDevices();
- var updateNotifier;
- function notifyUpdateAvailable() {
- updateNotifier = throttleTimeout(updateNotifier, null, 1e4, function() {
- var appName = chrome.runtime.getManifest().name;
- chrome.notifications.create("reload", {
- type: "basic",
- iconUrl: "/icon.png",
- title: appName,
- message: "There is an update available for Vysor.",
- buttons: [{
- title: "Reload"
- }]
- })
- })
- }
- chrome.runtime.onUpdateAvailable.addListener(function() {
- maybeClose()
- });
- chrome.notifications.onButtonClicked.addListener(function(nid, bid) {
- if (nid == "reload") {
- chrome.runtime.reload()
- } else if (nid == "never-start-automatically") {
- chrome.storage.local.set({
- "connect-automatically": false
- });
- if (list) {
- $(list.contentWindow.document).find("#connect-automatically-check").prop("checked", false)
- }
- chrome.notifications.clear(nid)
- }
- });
- chrome.notifications.onClicked.addListener(function(nid, bid) {});
- console.log("Vysor version", chrome.runtime.getManifest().version);
- console.log(navigator.userAgent)
- })();
Add Comment
Please, Sign In to add comment