mirror of
https://github.com/hensm/fx_cast.git
synced 2026-06-08 08:39:59 +00:00
Finish app conversion and enforce code style
This commit is contained in:
15
app/@types/bplist-creator/index.d.ts
vendored
Normal file
15
app/@types/bplist-creator/index.d.ts
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
|
||||||
|
declare module "bplist-creator" {
|
||||||
|
import Buffer from "buffer";
|
||||||
|
|
||||||
|
function bplist (dicts: object): Buffer;
|
||||||
|
export = bplist;
|
||||||
|
|
||||||
|
namespace bplist {
|
||||||
|
export class Real {
|
||||||
|
public value: number;
|
||||||
|
constructor (value: number);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
23
app/@types/bplist-parser/index.d.ts
vendored
Normal file
23
app/@types/bplist-parser/index.d.ts
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
|
||||||
|
declare module "bplist-parser" {
|
||||||
|
import Buffer from "buffer";
|
||||||
|
|
||||||
|
export var maxObjectSize: number;
|
||||||
|
export var maxObjectCount: number;
|
||||||
|
|
||||||
|
export class UID {
|
||||||
|
constructor (id: number);
|
||||||
|
UID: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParseFileCallback = (
|
||||||
|
err: string
|
||||||
|
, result?: Buffer) => void;
|
||||||
|
|
||||||
|
export function parseFile (
|
||||||
|
fileNameOrBuffer: Buffer | string
|
||||||
|
, callback: ParseFileCallback): void;
|
||||||
|
|
||||||
|
export function parseBuffer (buffer: Buffer): any;
|
||||||
|
}
|
||||||
63
app/@types/castv2/index.d.ts
vendored
63
app/@types/castv2/index.d.ts
vendored
@@ -1,16 +1,17 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
|
||||||
declare module "castv2" {
|
declare module "castv2" {
|
||||||
import { EventEmitter } from "events";
|
import { EventEmitter } from "events";
|
||||||
|
|
||||||
interface ClientConnectOptions {
|
interface ClientConnectOptions {
|
||||||
host: string
|
host: string;
|
||||||
, port?: number
|
port?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ClientConnectCallback {
|
type CallbackFunction = () => void;
|
||||||
(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ClientChannel extends EventEmitter {
|
|
||||||
|
export interface Channel extends EventEmitter {
|
||||||
bus: Client;
|
bus: Client;
|
||||||
sourceId: string;
|
sourceId: string;
|
||||||
destinationId: string;
|
destinationId: string;
|
||||||
@@ -21,41 +22,47 @@ declare module "castv2" {
|
|||||||
close (): void;
|
close (): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ServerListenCallback {
|
export interface DeviceAuthMessage {
|
||||||
(): void;
|
parse (data: any): any;
|
||||||
|
serialize (data: any): any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class Client extends EventEmitter {
|
export class Client extends EventEmitter {
|
||||||
connect (host: string, callback?: ClientConnectCallback): void;
|
public connect (
|
||||||
connect (options: ClientConnectOptions, callback: ClientConnectCallback): void;
|
options: ClientConnectOptions | string
|
||||||
|
, callback?: CallbackFunction): void;
|
||||||
|
|
||||||
close (): void;
|
public close (): void;
|
||||||
|
|
||||||
send (sourceId: string
|
public send (
|
||||||
, destinationId: string
|
sourceId: string
|
||||||
, namespace: string
|
, destinationId: string
|
||||||
, data: Buffer | string): void;
|
, namespace: string
|
||||||
|
, data: Buffer | string): void;
|
||||||
|
|
||||||
createChannel (sourceId: string
|
public createChannel (
|
||||||
, destinationId: string
|
sourceId: string
|
||||||
, namespace: string
|
, destinationId: string
|
||||||
, encoding: string): ClientChannel;
|
, namespace: string
|
||||||
|
, encoding: string): Channel;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Server {
|
export class Server extends EventEmitter {
|
||||||
constructor (options: object);
|
constructor (options: object);
|
||||||
|
|
||||||
listen (port: number
|
public listen (
|
||||||
|
port: number
|
||||||
, host: string
|
, host: string
|
||||||
, callback: ServerListenCallback): void;
|
, callback?: CallbackFunction): void;
|
||||||
|
|
||||||
send (clientId: string
|
public send (
|
||||||
, sourceId: string
|
clientId: string
|
||||||
, destinationId: string
|
, sourceId: string
|
||||||
, namespace: string
|
, destinationId: string
|
||||||
, data: Buffer | string): void;
|
, namespace: string
|
||||||
|
, data: Buffer | string): void;
|
||||||
|
|
||||||
close (): void;
|
public close (): void;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
55
app/@types/fast-srp-hap/index.d.ts
vendored
Normal file
55
app/@types/fast-srp-hap/index.d.ts
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/// <reference types="node" />
|
||||||
|
|
||||||
|
declare module "fast-srp-hap" {
|
||||||
|
import Buffer from "buffer";
|
||||||
|
|
||||||
|
interface Param {
|
||||||
|
N_length_bits: number;
|
||||||
|
N: any;
|
||||||
|
g: any;
|
||||||
|
hash: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const params: { [key: number]: Param };
|
||||||
|
|
||||||
|
type GenKeyCallback = (
|
||||||
|
err: string
|
||||||
|
, buf: Buffer) => void;
|
||||||
|
|
||||||
|
export function genKey (
|
||||||
|
bytes: number
|
||||||
|
, callback: GenKeyCallback): void;
|
||||||
|
|
||||||
|
export function computeVerifier (
|
||||||
|
params: object
|
||||||
|
, salt: Buffer
|
||||||
|
, I: Buffer
|
||||||
|
, P: Buffer): Buffer;
|
||||||
|
|
||||||
|
export class Client {
|
||||||
|
constructor (
|
||||||
|
params: object
|
||||||
|
, salt_buf: Buffer
|
||||||
|
, identity_buf: Buffer
|
||||||
|
, password_buf: Buffer
|
||||||
|
, secret1_buf: Buffer);
|
||||||
|
|
||||||
|
computeA (): Buffer;
|
||||||
|
setB(B_buf: Buffer): void;
|
||||||
|
computeM1 (): Buffer;
|
||||||
|
checkM2 (serverM2_buf: Buffer): void;
|
||||||
|
computeK (): Buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class Server {
|
||||||
|
constructor (
|
||||||
|
params: object
|
||||||
|
, verifier_buf: Buffer
|
||||||
|
, secret2_buf: Buffer);
|
||||||
|
|
||||||
|
computeB (): Buffer;
|
||||||
|
setA (A_buf: Buffer): void;
|
||||||
|
checkM1 (clientM1_buf: Buffer): Buffer;
|
||||||
|
computeK (): Buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
173
app/package-lock.json
generated
173
app/package-lock.json
generated
@@ -46,6 +46,15 @@
|
|||||||
"integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==",
|
"integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"@types/node-fetch": {
|
||||||
|
"version": "2.1.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.1.6.tgz",
|
||||||
|
"integrity": "sha512-Hv1jgh3pfpUEl2F2mqUd1AfLSk1YbUCeBJFaP36t7esAO617dErqdxWb5cdG2NfJGOofkmBW36fdx0dVewxDRg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "5.5.2",
|
"version": "5.5.2",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.2.tgz",
|
||||||
@@ -58,6 +67,12 @@
|
|||||||
"json-schema-traverse": "^0.3.0"
|
"json-schema-traverse": "^0.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"ansi-styles": {
|
"ansi-styles": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||||
@@ -67,6 +82,15 @@
|
|||||||
"color-convert": "^1.9.0"
|
"color-convert": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"argparse": {
|
||||||
|
"version": "1.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||||
|
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"sprintf-js": "~1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"arr-diff": {
|
"arr-diff": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
||||||
@@ -166,6 +190,44 @@
|
|||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
|
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"babel-code-frame": {
|
||||||
|
"version": "6.26.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
|
||||||
|
"integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"chalk": "^1.1.3",
|
||||||
|
"esutils": "^2.0.2",
|
||||||
|
"js-tokens": "^3.0.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-styles": {
|
||||||
|
"version": "2.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
|
||||||
|
"integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"chalk": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
|
||||||
|
"integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-styles": "^2.2.1",
|
||||||
|
"escape-string-regexp": "^1.0.2",
|
||||||
|
"has-ansi": "^2.0.0",
|
||||||
|
"strip-ansi": "^3.0.0",
|
||||||
|
"supports-color": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"supports-color": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-runtime": {
|
"babel-runtime": {
|
||||||
"version": "6.26.0",
|
"version": "6.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
"resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
|
||||||
@@ -336,6 +398,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/bufferview/-/bufferview-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/bufferview/-/bufferview-1.0.1.tgz",
|
||||||
"integrity": "sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0="
|
"integrity": "sha1-ev10pF+Tf6QiodM4wIu/3HbNcl0="
|
||||||
},
|
},
|
||||||
|
"builtin-modules": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
|
||||||
|
"integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"byline": {
|
"byline": {
|
||||||
"version": "5.0.0",
|
"version": "5.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/byline/-/byline-5.0.0.tgz",
|
||||||
@@ -468,6 +536,12 @@
|
|||||||
"delayed-stream": "~1.0.0"
|
"delayed-stream": "~1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"commander": {
|
||||||
|
"version": "2.19.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
|
||||||
|
"integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"component-emitter": {
|
"component-emitter": {
|
||||||
"version": "1.2.1",
|
"version": "1.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz",
|
||||||
@@ -594,6 +668,12 @@
|
|||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"diff": {
|
||||||
|
"version": "3.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
|
||||||
|
"integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"dir-glob": {
|
"dir-glob": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-2.0.0.tgz",
|
||||||
@@ -1024,6 +1104,15 @@
|
|||||||
"har-schema": "^2.0.0"
|
"har-schema": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"has-ansi": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"has-flag": {
|
"has-flag": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||||
@@ -1274,6 +1363,30 @@
|
|||||||
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
"integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"js-tokens": {
|
||||||
|
"version": "3.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
|
||||||
|
"integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"js-yaml": {
|
||||||
|
"version": "3.12.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.12.1.tgz",
|
||||||
|
"integrity": "sha512-um46hB9wNOKlwkHgiuyEVAybXBjwFUV0Z/RaHJblRd9DXltue9FTYvzCr9ErQrK9Adz5MU4gHWVaNUfdmrC8qA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"argparse": "^1.0.7",
|
||||||
|
"esprima": "^4.0.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"esprima": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||||
|
"dev": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"jsbn": {
|
"jsbn": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
|
||||||
@@ -1837,6 +1950,15 @@
|
|||||||
"throttleit": "^1.0.0"
|
"throttleit": "^1.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"resolve": {
|
||||||
|
"version": "1.10.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz",
|
||||||
|
"integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-parse": "^1.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"resolve-url": {
|
"resolve-url": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
|
||||||
@@ -2049,6 +2171,12 @@
|
|||||||
"extend-shallow": "^3.0.0"
|
"extend-shallow": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"sprintf-js": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"sshpk": {
|
"sshpk": {
|
||||||
"version": "1.15.2",
|
"version": "1.15.2",
|
||||||
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.15.2.tgz",
|
||||||
@@ -2124,6 +2252,15 @@
|
|||||||
"integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==",
|
"integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "5.5.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
@@ -2190,6 +2327,42 @@
|
|||||||
"punycode": "^1.4.1"
|
"punycode": "^1.4.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tslib": {
|
||||||
|
"version": "1.9.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
|
||||||
|
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"tslint": {
|
||||||
|
"version": "5.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tslint/-/tslint-5.13.0.tgz",
|
||||||
|
"integrity": "sha512-ECOOQRxXCYnUUePG5h/+Z1Zouobk3KFpIHA9aKBB/nnMxs97S1JJPDGt5J4cGm1y9U9VmVlfboOxA8n1kSNzGw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"babel-code-frame": "^6.22.0",
|
||||||
|
"builtin-modules": "^1.1.1",
|
||||||
|
"chalk": "^2.3.0",
|
||||||
|
"commander": "^2.12.1",
|
||||||
|
"diff": "^3.2.0",
|
||||||
|
"glob": "^7.1.1",
|
||||||
|
"js-yaml": "^3.7.0",
|
||||||
|
"minimatch": "^3.0.4",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"resolve": "^1.3.2",
|
||||||
|
"semver": "^5.3.0",
|
||||||
|
"tslib": "^1.8.0",
|
||||||
|
"tsutils": "^2.27.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tsutils": {
|
||||||
|
"version": "2.29.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
|
||||||
|
"integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"tslib": "^1.8.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"tunnel-agent": {
|
"tunnel-agent": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||||
|
|||||||
@@ -8,7 +8,8 @@
|
|||||||
"build": "node bin/build.js",
|
"build": "node bin/build.js",
|
||||||
"package": "node bin/build.js --package",
|
"package": "node bin/build.js --package",
|
||||||
"install-manifest": "node bin/install-manifest.js",
|
"install-manifest": "node bin/install-manifest.js",
|
||||||
"remove-manifest": "node bin/install-manifest.js --remove"
|
"remove-manifest": "node bin/install-manifest.js --remove",
|
||||||
|
"lint": "tslint -c tslint.json -p ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"bplist-creator": "0.0.7",
|
"bplist-creator": "0.0.7",
|
||||||
@@ -24,8 +25,10 @@
|
|||||||
"@types/dnssd": "^0.4.1",
|
"@types/dnssd": "^0.4.1",
|
||||||
"@types/mime-types": "^2.1.0",
|
"@types/mime-types": "^2.1.0",
|
||||||
"@types/node": "^11.9.5",
|
"@types/node": "^11.9.5",
|
||||||
|
"@types/node-fetch": "^2.1.6",
|
||||||
"mustache": "^3.0.1",
|
"mustache": "^3.0.1",
|
||||||
"pkg": "^4.3.5"
|
"pkg": "^4.3.5",
|
||||||
|
"tslint": "^5.13.0"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"rage-edit": "^1.2.0"
|
"rage-edit": "^1.2.0"
|
||||||
|
|||||||
@@ -25,25 +25,24 @@ export interface UpdateMessageData {
|
|||||||
export default class Media {
|
export default class Media {
|
||||||
private sessionId: number;
|
private sessionId: number;
|
||||||
private mediaSessionId: number;
|
private mediaSessionId: number;
|
||||||
private _id: string;
|
private referenceId: string;
|
||||||
private session: Session;
|
private session: Session;
|
||||||
private channel: any;
|
private channel: any;
|
||||||
private _sendMessage: SendMessageCallback;
|
private sendMessageCallback: SendMessageCallback;
|
||||||
|
|
||||||
constructor (sessionId: number
|
constructor (
|
||||||
, mediaSessionId: number
|
sessionId: number
|
||||||
, _id: string
|
, mediaSessionId: number
|
||||||
, parentSession: Session,
|
, referenceId: string
|
||||||
_sendMessage: SendMessageCallback) {
|
, session: Session
|
||||||
|
, sendMessageCallback: SendMessageCallback) {
|
||||||
this._id = _id;
|
|
||||||
|
|
||||||
this._sendMessage = _sendMessage;
|
|
||||||
|
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
this.mediaSessionId = mediaSessionId;
|
this.mediaSessionId = mediaSessionId;
|
||||||
|
this.referenceId = referenceId;
|
||||||
|
this.session = session;
|
||||||
|
this.sendMessageCallback = sendMessageCallback;
|
||||||
|
|
||||||
this.session = parentSession;
|
|
||||||
this.session.createChannel(MEDIA_NAMESPACE);
|
this.session.createChannel(MEDIA_NAMESPACE);
|
||||||
this.channel = this.session.channelMap.get(MEDIA_NAMESPACE);
|
this.channel = this.session.channelMap.get(MEDIA_NAMESPACE);
|
||||||
|
|
||||||
@@ -54,11 +53,12 @@ export default class Media {
|
|||||||
const status = data.status[0];
|
const status = data.status[0];
|
||||||
|
|
||||||
const messageData = {
|
const messageData = {
|
||||||
currentTime: status.currentTime
|
_lastCurrentTime: Date.now() / 1000
|
||||||
, _lastCurrentTime: Date.now() / 1000
|
|
||||||
, customData: status.customData
|
|
||||||
, _volumeLevel: status.volume.level
|
, _volumeLevel: status.volume.level
|
||||||
, _volumeMuted: status.volume.muted
|
, _volumeMuted: status.volume.muted
|
||||||
|
|
||||||
|
, currentTime: status.currentTime
|
||||||
|
, customData: status.customData
|
||||||
, playbackRate: status.playbackRate
|
, playbackRate: status.playbackRate
|
||||||
, playerState: status.playerState
|
, playerState: status.playerState
|
||||||
, repeatMode: status.repeatMode
|
, repeatMode: status.repeatMode
|
||||||
@@ -81,7 +81,7 @@ export default class Media {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
messageHandler (message: Message) {
|
public messageHandler (message: Message) {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "bridge:/media/sendMediaMessage": {
|
case "bridge:/media/sendMediaMessage": {
|
||||||
let error = false;
|
let error = false;
|
||||||
@@ -97,15 +97,15 @@ export default class Media {
|
|||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage (subject: string, data: any = {}) {
|
private sendMessage (subject: string, data: any = {}) {
|
||||||
this._sendMessage({
|
this.sendMessageCallback({
|
||||||
subject
|
subject
|
||||||
, data
|
, data
|
||||||
, _id: this._id
|
, _id: this.referenceId
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import { Client, ClientChannel } from "castv2";
|
import uuid from "uuid";
|
||||||
|
|
||||||
|
import { Channel, Client } from "castv2";
|
||||||
|
|
||||||
import { Message
|
import { Message
|
||||||
, SendMessageCallback } from "./types";
|
, SendMessageCallback } from "./types";
|
||||||
@@ -11,40 +13,39 @@ const NS_HEARTBEAT = "urn:x-cast:com.google.cast.tp.heartbeat";
|
|||||||
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
const NS_RECEIVER = "urn:x-cast:com.google.cast.receiver";
|
||||||
|
|
||||||
export default class Session {
|
export default class Session {
|
||||||
private _sendMessage: SendMessageCallback;
|
public channelMap = new Map<string, Channel>();
|
||||||
|
|
||||||
|
private sendMessageCallback: SendMessageCallback;
|
||||||
private sessionId: number;
|
private sessionId: number;
|
||||||
private _id: string;
|
private referenceId: string;
|
||||||
|
|
||||||
private client: Client;
|
private client: Client;
|
||||||
private clientConnection: ClientChannel;
|
private clientConnection: Channel;
|
||||||
private clientHeartbeat: ClientChannel;
|
private clientHeartbeat: Channel;
|
||||||
private clientReceiver: ClientChannel;
|
private clientReceiver: Channel;
|
||||||
private clientHeartbeatIntervalId: NodeJS.Timer;
|
private clientHeartbeatIntervalId: NodeJS.Timer;
|
||||||
|
|
||||||
private isSessionCreated = false;
|
private isSessionCreated = false;
|
||||||
|
|
||||||
private clientId: string;
|
private clientId: string;
|
||||||
private transportId: string;
|
private transportId: string;
|
||||||
private transportConnection: ClientChannel;
|
private transportConnection: Channel;
|
||||||
private app: any;
|
private app: any;
|
||||||
|
|
||||||
|
constructor (
|
||||||
|
host: string
|
||||||
|
, port: number
|
||||||
|
, appId: string
|
||||||
|
, sessionId: number
|
||||||
|
, sendMessageCallback: SendMessageCallback) {
|
||||||
|
|
||||||
public channelMap = new Map<string, ClientChannel>();
|
this.sendMessageCallback = sendMessageCallback;
|
||||||
|
|
||||||
|
|
||||||
constructor (host: string
|
|
||||||
, port: number
|
|
||||||
, appId: string
|
|
||||||
, sessionId: number
|
|
||||||
, _sendMessage: SendMessageCallback) {
|
|
||||||
|
|
||||||
this._sendMessage = _sendMessage;
|
|
||||||
this.sessionId = sessionId;
|
this.sessionId = sessionId;
|
||||||
|
|
||||||
this.client = new Client();
|
this.client = new Client();
|
||||||
|
|
||||||
this.client.connect({ host, port }, () => {
|
this.client.connect({ host, port }, () => {
|
||||||
let transportHeartbeat: ClientChannel;
|
let transportHeartbeat: Channel;
|
||||||
|
|
||||||
const sourceId = "sender-0";
|
const sourceId = "sender-0";
|
||||||
const destinationId = "receiver-0";
|
const destinationId = "receiver-0";
|
||||||
@@ -63,6 +64,7 @@ export default class Session {
|
|||||||
if (transportHeartbeat) {
|
if (transportHeartbeat) {
|
||||||
transportHeartbeat.send({ type: "PING" });
|
transportHeartbeat.send({ type: "PING" });
|
||||||
}
|
}
|
||||||
|
|
||||||
this.clientHeartbeat.send({ type: "PING" });
|
this.clientHeartbeat.send({ type: "PING" });
|
||||||
}, 5000);
|
}, 5000);
|
||||||
|
|
||||||
@@ -73,56 +75,58 @@ export default class Session {
|
|||||||
});
|
});
|
||||||
|
|
||||||
this.clientReceiver.on("message", (message: any) => {
|
this.clientReceiver.on("message", (message: any) => {
|
||||||
switch (message.type) {
|
if (message.type === "RECEIVER_STATUS") {
|
||||||
case "RECEIVER_STATUS": {
|
this.sendMessage("shim:/session/updateStatus"
|
||||||
this.sendMessage("shim:/session/updateStatus", message.status);
|
, message.status);
|
||||||
|
|
||||||
if (!message.status.applications) return;
|
if (!message.status.applications) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const receiverApp = message.status.applications[0];
|
const receiverApp = message.status.applications[0];
|
||||||
const receiverAppId = receiverApp.appId;
|
const receiverAppId = receiverApp.appId;
|
||||||
|
|
||||||
this.app = receiverApp;
|
this.app = receiverApp;
|
||||||
|
|
||||||
if (receiverAppId !== appId) {
|
if (receiverAppId !== appId) {
|
||||||
// Close session
|
// Close session
|
||||||
this.sendMessage("shim:/session/stopped");
|
this.sendMessage("shim:/session/stopped");
|
||||||
this.client.close();
|
this.client.close();
|
||||||
clearInterval(this.clientHeartbeatIntervalId);
|
clearInterval(this.clientHeartbeatIntervalId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isSessionCreated) {
|
if (!this.isSessionCreated) {
|
||||||
this.isSessionCreated = true;
|
this.isSessionCreated = true;
|
||||||
|
|
||||||
this.transportId = this.app.transportId;
|
this.transportId = this.app.transportId;
|
||||||
this.clientId = `client-${Math.floor(Math.random() * 10e5)}`;
|
this.clientId =
|
||||||
|
`client-${Math.floor(Math.random() * 10e5)}`;
|
||||||
|
|
||||||
this.transportConnection = this.client.createChannel(
|
this.transportConnection = this.client.createChannel(
|
||||||
this.clientId, this.transportId, NS_CONNECTION, "JSON");
|
this.clientId, this.transportId
|
||||||
transportHeartbeat = this.client.createChannel(
|
, NS_CONNECTION, "JSON");
|
||||||
this.clientId, this.transportId, NS_HEARTBEAT, "JSON");
|
transportHeartbeat = this.client.createChannel(
|
||||||
|
this.clientId, this.transportId
|
||||||
|
, NS_HEARTBEAT, "JSON");
|
||||||
|
|
||||||
this.transportConnection.send({ type: "CONNECT" });
|
this.transportConnection.send({ type: "CONNECT" });
|
||||||
|
|
||||||
this.sessionId = this.app.sessionId;
|
this.sessionId = this.app.sessionId;
|
||||||
|
|
||||||
this.sendMessage("shim:/session/connected", {
|
this.sendMessage("shim:/session/connected", {
|
||||||
sessionId: this.app.sessionId
|
sessionId: this.app.sessionId
|
||||||
, namespaces: this.app.namespaces
|
, namespaces: this.app.namespaces
|
||||||
, displayName: this.app.displayName
|
, displayName: this.app.displayName
|
||||||
, statusText: this.app.displayName
|
, statusText: this.app.displayName
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
messageHandler (message: Message) {
|
public messageHandler (message: Message) {
|
||||||
switch (message.subject) {
|
switch (message.subject) {
|
||||||
case "bridge:/session/close":
|
case "bridge:/session/close":
|
||||||
this.close();
|
this.close();
|
||||||
@@ -136,7 +140,7 @@ export default class Session {
|
|||||||
this._impl_sendMessage(
|
this._impl_sendMessage(
|
||||||
message.data.namespace
|
message.data.namespace
|
||||||
, message.data.message
|
, message.data.message
|
||||||
, message.data.messageId)
|
, message.data.messageId);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case "bridge:/session/impl_setReceiverMuted":
|
case "bridge:/session/impl_setReceiverMuted":
|
||||||
@@ -157,15 +161,7 @@ export default class Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sendMessage (subject: string, data: any = {}) {
|
public createChannel (namespace: string) {
|
||||||
this._sendMessage({
|
|
||||||
subject
|
|
||||||
, data
|
|
||||||
, _id: this._id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
createChannel (namespace: string) {
|
|
||||||
if (!this.channelMap.has(namespace)) {
|
if (!this.channelMap.has(namespace)) {
|
||||||
this.channelMap.set(namespace
|
this.channelMap.set(namespace
|
||||||
, this.client.createChannel(
|
, this.client.createChannel(
|
||||||
@@ -173,25 +169,36 @@ export default class Session {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
close () {
|
public close () {
|
||||||
this.clientConnection.send({ type: "CLOSE" });
|
this.clientConnection.send({ type: "CLOSE" });
|
||||||
if (this.transportConnection) {
|
if (this.transportConnection) {
|
||||||
this.transportConnection.send({ type: "CLOSE" });
|
this.transportConnection.send({ type: "CLOSE" });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private sendMessage (subject: string, data: any = {}) {
|
||||||
|
this.sendMessageCallback({
|
||||||
|
subject
|
||||||
|
, data
|
||||||
|
, _id: this.referenceId
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
_impl_addMessageListener (namespace: string) {
|
private _impl_addMessageListener (namespace: string) {
|
||||||
this.createChannel(namespace);
|
this.createChannel(namespace);
|
||||||
this.channelMap.get(namespace).on("message", (data: any) => {
|
this.channelMap.get(namespace).on("message", (data: any) => {
|
||||||
this.sendMessage("shim:/session/impl_addMessageListener", {
|
this.sendMessage("shim:/session/impl_addMessageListener", {
|
||||||
namespace: namespace
|
namespace
|
||||||
, data: JSON.stringify(data)
|
, data: JSON.stringify(data)
|
||||||
});
|
});
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl_sendMessage (namespace: string, message: object, messageId: string) {
|
private _impl_sendMessage (
|
||||||
|
namespace: string
|
||||||
|
, message: object
|
||||||
|
, messageId: string) {
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -207,7 +214,8 @@ export default class Session {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl_setReceiverMuted (muted: boolean, volumeId: string) {
|
private _impl_setReceiverMuted (muted: boolean, volumeId: string) {
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -226,7 +234,8 @@ export default class Session {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl_setReceiverVolumeLevel (newLevel: number, volumeId: string) {
|
private _impl_setReceiverVolumeLevel (newLevel: number, volumeId: string) {
|
||||||
|
|
||||||
let error = false;
|
let error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -234,7 +243,7 @@ export default class Session {
|
|||||||
type: "SET_VOLUME"
|
type: "SET_VOLUME"
|
||||||
, volume: { level: newLevel }
|
, volume: { level: newLevel }
|
||||||
, requestId: 0
|
, requestId: 0
|
||||||
})
|
});
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
error = true;
|
error = true;
|
||||||
}
|
}
|
||||||
@@ -245,7 +254,7 @@ export default class Session {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_impl_stop (stopId: string) {
|
private _impl_stop (stopId: string) {
|
||||||
let error = false;
|
let error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -8,10 +8,10 @@
|
|||||||
* - https://github.com/postlund/pyatv/blob/master/docs/airplay.rst
|
* - https://github.com/postlund/pyatv/blob/master/docs/airplay.rst
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import nacl from "tweetnacl";
|
|
||||||
import srp6a from "fast-srp-hap";
|
|
||||||
import crypto from "crypto";
|
import crypto from "crypto";
|
||||||
import fetch from "node-fetch";
|
import srp6a from "fast-srp-hap";
|
||||||
|
import fetch, { Headers } from "node-fetch";
|
||||||
|
import nacl from "tweetnacl";
|
||||||
import bplist from "./bplist";
|
import bplist from "./bplist";
|
||||||
|
|
||||||
|
|
||||||
@@ -22,7 +22,11 @@ const MIMETYPE_BPLIST = "application/x-apple-binary-plist";
|
|||||||
* Client ID and keypair
|
* Client ID and keypair
|
||||||
*/
|
*/
|
||||||
export class AirPlayAuthCredentials {
|
export class AirPlayAuthCredentials {
|
||||||
constructor (clientId, clientSk) {
|
public clientId: string;
|
||||||
|
public clientSk: Uint8Array;
|
||||||
|
public clientPk: Uint8Array;
|
||||||
|
|
||||||
|
constructor (clientId: string, clientSk: Uint8Array) {
|
||||||
if (clientId && clientSk) {
|
if (clientId && clientSk) {
|
||||||
this.clientId = clientId;
|
this.clientId = clientId;
|
||||||
this.clientSk = clientSk;
|
this.clientSk = clientSk;
|
||||||
@@ -40,11 +44,13 @@ export class AirPlayAuthCredentials {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class AirPlayAuth {
|
export class AirPlayAuth {
|
||||||
constructor (address, credentials) {
|
private address: string;
|
||||||
|
private credentials: AirPlayAuthCredentials;
|
||||||
|
private baseUrl: URL;
|
||||||
|
|
||||||
|
constructor (address: string, credentials: AirPlayAuthCredentials) {
|
||||||
this.address = address;
|
this.address = address;
|
||||||
this.clientId = credentials.clientId;
|
this.credentials = credentials;
|
||||||
this.clientSk = credentials.clientSk;
|
|
||||||
this.clientPk = credentials.clientPk;
|
|
||||||
|
|
||||||
this.baseUrl = new URL(`http://${this.address}:${AIRPLAY_PORT}`);
|
this.baseUrl = new URL(`http://${this.address}:${AIRPLAY_PORT}`);
|
||||||
}
|
}
|
||||||
@@ -52,7 +58,7 @@ export class AirPlayAuth {
|
|||||||
/**
|
/**
|
||||||
* Begins pairing process.
|
* Begins pairing process.
|
||||||
*/
|
*/
|
||||||
async beginPairing () {
|
public async beginPairing () {
|
||||||
return this.sendPostRequest("/pair-pin-start");
|
return this.sendPostRequest("/pair-pin-start");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,7 +67,7 @@ export class AirPlayAuth {
|
|||||||
* beginPairing(). Coordinates the three pairing stages and
|
* beginPairing(). Coordinates the three pairing stages and
|
||||||
* manages request responses.
|
* manages request responses.
|
||||||
*/
|
*/
|
||||||
async finishPairing (pin) {
|
public async finishPairing (pin: string) {
|
||||||
// Stage 1 response
|
// Stage 1 response
|
||||||
const { pk: serverPk
|
const { pk: serverPk
|
||||||
, salt: serverSalt } = await this.pairSetupPin1();
|
, salt: serverSalt } = await this.pairSetupPin1();
|
||||||
@@ -72,11 +78,11 @@ export class AirPlayAuth {
|
|||||||
|
|
||||||
// Create SRP client
|
// Create SRP client
|
||||||
const srpClient = new srp6a.Client(
|
const srpClient = new srp6a.Client(
|
||||||
srpParams // Params
|
srpParams // Params
|
||||||
, serverSalt // Receiver salt
|
, serverSalt // Receiver salt
|
||||||
, Buffer.from(this.clientId) // Username
|
, Buffer.from(this.credentials.clientId) // Username
|
||||||
, Buffer.from(pin) // Password (receiver pin)
|
, Buffer.from(pin) // Password (receiver pin)
|
||||||
, Buffer.from(this.clientSk)); // Client secret key
|
, Buffer.from(this.credentials.clientSk)); // Client secret key
|
||||||
|
|
||||||
// Add receiver's public key
|
// Add receiver's public key
|
||||||
srpClient.setB(serverPk);
|
srpClient.setB(serverPk);
|
||||||
@@ -87,7 +93,7 @@ export class AirPlayAuth {
|
|||||||
, srpClient.computeM1()); // SRP proof
|
, srpClient.computeM1()); // SRP proof
|
||||||
|
|
||||||
// Stage 3 response
|
// Stage 3 response
|
||||||
console.log(await this.pairSetupPin3(srpClient.computeK()));
|
await this.pairSetupPin3(srpClient.computeK());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,12 +102,12 @@ export class AirPlayAuth {
|
|||||||
* Triggering the receiver passcode display and receiving
|
* Triggering the receiver passcode display and receiving
|
||||||
* its public key / salt.
|
* its public key / salt.
|
||||||
*/
|
*/
|
||||||
async pairSetupPin1 () {
|
public async pairSetupPin1 (): Promise<any> {
|
||||||
const [ response ] = await this.sendPostRequestBplist(
|
const [ response ] = await this.sendPostRequestBplist(
|
||||||
"/pair-setup-pin"
|
"/pair-setup-pin"
|
||||||
, {
|
, {
|
||||||
method: "pin"
|
method: "pin"
|
||||||
, user: this.clientId
|
, user: this.credentials.clientId
|
||||||
});
|
});
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@@ -114,7 +120,10 @@ export class AirPlayAuth {
|
|||||||
* public keys, sending them to the receiver and receiving its
|
* public keys, sending them to the receiver and receiving its
|
||||||
* proof.
|
* proof.
|
||||||
*/
|
*/
|
||||||
async pairSetupPin2 (pk, proof) {
|
public async pairSetupPin2 (
|
||||||
|
pk: Buffer
|
||||||
|
, proof: Buffer): Promise<any> {
|
||||||
|
|
||||||
const [ response ] = await this.sendPostRequestBplist(
|
const [ response ] = await this.sendPostRequestBplist(
|
||||||
"/pair-setup-pin"
|
"/pair-setup-pin"
|
||||||
, { pk, proof });
|
, { pk, proof });
|
||||||
@@ -129,7 +138,9 @@ export class AirPlayAuth {
|
|||||||
* secret hash and sending it to the receiver. Receiver then
|
* secret hash and sending it to the receiver. Receiver then
|
||||||
* responds confirming the pairing is complete.
|
* responds confirming the pairing is complete.
|
||||||
*/
|
*/
|
||||||
async pairSetupPin3 (sharedSecretHash) {
|
public async pairSetupPin3 (
|
||||||
|
sharedSecretHash: crypto.BinaryLike): Promise<any> {
|
||||||
|
|
||||||
// Create AES key
|
// Create AES key
|
||||||
const aesKey = crypto.createHash("sha512")
|
const aesKey = crypto.createHash("sha512")
|
||||||
.update("Pair-Setup-AES-Key")
|
.update("Pair-Setup-AES-Key")
|
||||||
@@ -150,7 +161,7 @@ export class AirPlayAuth {
|
|||||||
const cipher = crypto.createCipheriv("aes-128-gcm", aesKey, aesIv);
|
const cipher = crypto.createCipheriv("aes-128-gcm", aesKey, aesIv);
|
||||||
|
|
||||||
// Encode client public key
|
// Encode client public key
|
||||||
const epk = cipher.update(this.clientPk);
|
const epk = cipher.update(this.credentials.clientPk);
|
||||||
cipher.final();
|
cipher.final();
|
||||||
const authTag = cipher.getAuthTag();
|
const authTag = cipher.getAuthTag();
|
||||||
|
|
||||||
@@ -166,7 +177,11 @@ export class AirPlayAuth {
|
|||||||
* Sends a POST request to receiver and returns the
|
* Sends a POST request to receiver and returns the
|
||||||
* response.
|
* response.
|
||||||
*/
|
*/
|
||||||
async sendPostRequest (path, contentType, data) {
|
public async sendPostRequest (
|
||||||
|
path: string
|
||||||
|
, contentType?: string
|
||||||
|
, data?: Buffer | string): Promise<any> {
|
||||||
|
|
||||||
// Create URL from base receiver URL and path
|
// Create URL from base receiver URL and path
|
||||||
const requestUrl = new URL(path, this.baseUrl);
|
const requestUrl = new URL(path, this.baseUrl);
|
||||||
|
|
||||||
@@ -189,24 +204,26 @@ export class AirPlayAuth {
|
|||||||
throw new Error(`AirPlay request error: ${response.status}`);
|
throw new Error(`AirPlay request error: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
return await response.arrayBuffer();
|
return await response.buffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encodes binary plist data, sends a POST request to
|
* Encodes binary plist data, sends a POST request to
|
||||||
* receiver, then decodes and returns the response.
|
* receiver, then decodes and returns the response.
|
||||||
*/
|
*/
|
||||||
async sendPostRequestBplist (path, data) {
|
public async sendPostRequestBplist (
|
||||||
|
path: string
|
||||||
|
, data?: object): Promise<any> {
|
||||||
|
|
||||||
// Convert data to compatible type
|
// Convert data to compatible type
|
||||||
const requestBody = data
|
const requestBody = data
|
||||||
? bplist.create(data)
|
? bplist.create(data)
|
||||||
: null;
|
: undefined;
|
||||||
|
|
||||||
const responseArrayBuffer = await this.sendPostRequest(
|
const response = await this.sendPostRequest(
|
||||||
path, MIMETYPE_BPLIST, requestBody);
|
path, MIMETYPE_BPLIST, requestBody);
|
||||||
|
|
||||||
// Convert response data to Buffer for bplist-parser
|
// Convert response data to Buffer for bplist-parser
|
||||||
return bplist.parse.parseBuffer(
|
return bplist.parse.parseBuffer(response);
|
||||||
Buffer.from(responseArrayBuffer));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import create from "bplist-creator";
|
import create from "bplist-creator";
|
||||||
import parse from "bplist-parser";
|
import parse from "bplist-parser";
|
||||||
|
|
||||||
export default { create, parse };
|
export default { create, parse };
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
import dnssd from "dnssd";
|
import dnssd from "dnssd";
|
||||||
|
|
||||||
import http from "http";
|
import events from "events";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import path from "path";
|
import http from "http";
|
||||||
import mime from "mime-types";
|
import mime from "mime-types";
|
||||||
|
import path from "path";
|
||||||
|
|
||||||
import * as transforms from "./transforms";
|
|
||||||
import Media from "./Media";
|
import Media from "./Media";
|
||||||
import Session from "./Session";
|
import Session from "./Session";
|
||||||
|
import * as transforms from "./transforms";
|
||||||
|
|
||||||
import { Message } from "./types";
|
import { Message } from "./types";
|
||||||
|
|
||||||
@@ -15,18 +16,21 @@ import { __applicationName
|
|||||||
, __applicationVersion } from "../package.json";
|
, __applicationVersion } from "../package.json";
|
||||||
|
|
||||||
|
|
||||||
|
// Increase listener limit
|
||||||
|
events.EventEmitter.defaultMaxListeners = 50;
|
||||||
|
|
||||||
|
|
||||||
const browser = new dnssd.Browser(dnssd.tcp("googlecast"));
|
const browser = new dnssd.Browser(dnssd.tcp("googlecast"));
|
||||||
|
|
||||||
// Local media server
|
// Local media server
|
||||||
let httpServer: http.Server;
|
let httpServer: http.Server;
|
||||||
|
|
||||||
process.on("SIGTERM", () => {
|
process.on("SIGTERM", () => {
|
||||||
if (httpServer) httpServer.close();
|
if (httpServer) {
|
||||||
|
httpServer.close();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// Increase listener limit
|
|
||||||
require("events").EventEmitter.defaultMaxListeners = 50;
|
|
||||||
|
|
||||||
// stdin -> stdout
|
// stdin -> stdout
|
||||||
process.stdin
|
process.stdin
|
||||||
.pipe(transforms.decode)
|
.pipe(transforms.decode)
|
||||||
@@ -40,7 +44,9 @@ process.stdin
|
|||||||
function sendMessage (message: object) {
|
function sendMessage (message: object) {
|
||||||
try {
|
try {
|
||||||
transforms.encode.write(message);
|
transforms.encode.write(message);
|
||||||
} catch (err) {}
|
} catch (err) {
|
||||||
|
console.error("Failed to encode message");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,12 +108,12 @@ async function handleMessage (message: Message) {
|
|||||||
case "bridge:/getInfo": {
|
case "bridge:/getInfo": {
|
||||||
const extensionVersion = message.data;
|
const extensionVersion = message.data;
|
||||||
return __applicationVersion;
|
return __applicationVersion;
|
||||||
};
|
}
|
||||||
|
|
||||||
case "bridge:/startDiscovery": {
|
case "bridge:/startDiscovery": {
|
||||||
browser.start();
|
browser.start();
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
case "bridge:/startHttpServer": {
|
case "bridge:/startHttpServer": {
|
||||||
const { filePath, port } = message.data;
|
const { filePath, port } = message.data;
|
||||||
@@ -144,7 +150,7 @@ async function handleMessage (message: Message) {
|
|||||||
, "Content-Type": contentType
|
, "Content-Type": contentType
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.createReadStream(filePath).pipe(res)
|
fs.createReadStream(filePath).pipe(res);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -155,12 +161,14 @@ async function handleMessage (message: Message) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
|
|
||||||
case "bridge:/stopHttpServer": {
|
case "bridge:/stopHttpServer": {
|
||||||
if (httpServer) httpServer.close();
|
if (httpServer) {
|
||||||
|
httpServer.close();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -180,7 +188,7 @@ browser.on("serviceUp", (service: dnssd.Service) => {
|
|||||||
|
|
||||||
browser.on("serviceDown", (service: dnssd.Service) => {
|
browser.on("serviceDown", (service: dnssd.Service) => {
|
||||||
transforms.encode.write({
|
transforms.encode.write({
|
||||||
subject:"shim:/serviceDown"
|
subject: "shim:/serviceDown"
|
||||||
, data: {
|
, data: {
|
||||||
id: service.txt.id
|
id: service.txt.id
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,9 +4,7 @@ import { Transform } from "stream";
|
|||||||
import { Message } from "./types";
|
import { Message } from "./types";
|
||||||
|
|
||||||
|
|
||||||
interface ResponseHandlerFunction {
|
type ResponseHandlerFunction = (message: Message) => Promise<any>;
|
||||||
(message: Message): Promise<any>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Takes a handler function that implements the transform
|
* Takes a handler function that implements the transform
|
||||||
@@ -18,9 +16,9 @@ export const response = (handler: ResponseHandlerFunction) => new Transform({
|
|||||||
|
|
||||||
, transform (chunk: Message, encoding, callback) {
|
, transform (chunk: Message, encoding, callback) {
|
||||||
Promise.resolve(handler(chunk))
|
Promise.resolve(handler(chunk))
|
||||||
.then(response => {
|
.then(res => {
|
||||||
if (response) {
|
if (res) {
|
||||||
callback(null, response);
|
callback(null, res);
|
||||||
} else {
|
} else {
|
||||||
callback(null);
|
callback(null);
|
||||||
}
|
}
|
||||||
@@ -94,13 +92,13 @@ export const encode = new Transform({
|
|||||||
writableObjectMode: true
|
writableObjectMode: true
|
||||||
|
|
||||||
, transform (chunk, encoding, callback) {
|
, transform (chunk, encoding, callback) {
|
||||||
const message_length = Buffer.alloc(4);
|
const messageLength = Buffer.alloc(4);
|
||||||
const message = Buffer.from(JSON.stringify(chunk));
|
const message = Buffer.from(JSON.stringify(chunk));
|
||||||
|
|
||||||
// Write message length
|
// Write message length
|
||||||
message_length.writeUInt32LE(message.length, 0);
|
messageLength.writeUInt32LE(message.length, 0);
|
||||||
|
|
||||||
// Output joined message length and content
|
// Output joined message length and content
|
||||||
callback(null, Buffer.concat([message_length, message]));
|
callback(null, Buffer.concat([messageLength, message]));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -6,6 +6,4 @@ export interface Message {
|
|||||||
_id?: string;
|
_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SendMessageCallback {
|
export type SendMessageCallback = (message: Message) => void;
|
||||||
(message: Message): void
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
, "esModuleInterop": true
|
, "esModuleInterop": true
|
||||||
, "resolveJsonModule": true
|
, "resolveJsonModule": true
|
||||||
, "removeComments": true
|
, "removeComments": true
|
||||||
|
, "downlevelIteration": true
|
||||||
}
|
}
|
||||||
, "include": [
|
, "include": [
|
||||||
"./src/**/*"
|
"./src/**/*"
|
||||||
|
|||||||
24
app/tslint.json
Normal file
24
app/tslint.json
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"defaultSeverity": "error"
|
||||||
|
, "extends": [
|
||||||
|
"tslint:recommended"
|
||||||
|
]
|
||||||
|
, "jsRules": {}
|
||||||
|
, "rules": {
|
||||||
|
"no-consecutive-blank-lines": false
|
||||||
|
, "arrow-parens": false
|
||||||
|
, "interface-name": false
|
||||||
|
, "max-classes-per-file": false
|
||||||
|
, "max-line-length": [ true, {
|
||||||
|
"limit": 80
|
||||||
|
, "ignore-pattern": "//"
|
||||||
|
}]
|
||||||
|
, "no-console": [ true, "log" ]
|
||||||
|
, "object-literal-sort-keys": false
|
||||||
|
, "radix": false
|
||||||
|
, "semicolon": [ true, "always" ]
|
||||||
|
, "space-before-function-paren": [ true, "always" ]
|
||||||
|
, "trailing-comma": false
|
||||||
|
}
|
||||||
|
, "rulesDirectory": []
|
||||||
|
}
|
||||||
@@ -17,7 +17,6 @@
|
|||||||
"preact": "^8.4.2",
|
"preact": "^8.4.2",
|
||||||
"preact-compat": "^3.18.4",
|
"preact-compat": "^3.18.4",
|
||||||
"ts-loader": "^5.3.3",
|
"ts-loader": "^5.3.3",
|
||||||
"uuid": "^3.3.2",
|
|
||||||
"web-ext": "^2.9.1",
|
"web-ext": "^2.9.1",
|
||||||
"webpack": "^4.27.0",
|
"webpack": "^4.27.0",
|
||||||
"webpack-cli": "^3.1.2"
|
"webpack-cli": "^3.1.2"
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"allowJs": true
|
"allowJs": true
|
||||||
, "sourceMap": true
|
|
||||||
, "target": "es6"
|
|
||||||
, "noImplicitAny": true
|
|
||||||
, "esModuleInterop": true
|
, "esModuleInterop": true
|
||||||
, "moduleResolution": "node"
|
|
||||||
, "resolveJsonModule": true
|
|
||||||
, "removeComments": true
|
|
||||||
, "jsx": "react"
|
, "jsx": "react"
|
||||||
, "lib": [ "esnext", "dom" ]
|
, "lib": [ "esnext", "dom" ]
|
||||||
|
, "moduleResolution": "node"
|
||||||
|
, "noImplicitAny": true
|
||||||
|
, "removeComments": true
|
||||||
|
, "resolveJsonModule": true
|
||||||
|
, "sourceMap": true
|
||||||
|
, "target": "es6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
package-lock.json
generated
21
package-lock.json
generated
@@ -2,6 +2,21 @@
|
|||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/node": {
|
||||||
|
"version": "11.9.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-11.9.5.tgz",
|
||||||
|
"integrity": "sha512-vVjM0SVzgaOUpflq4GYBvCpozes8OgIIS5gVXVka+OfK3hvnkC1i93U8WiY2OtNE4XUWyyy/86Kf6e0IHTQw1Q==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
|
"@types/uuid": {
|
||||||
|
"version": "3.4.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
|
||||||
|
"integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"@types/node": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ansi-regex": {
|
"ansi-regex": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
@@ -468,6 +483,12 @@
|
|||||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"uuid": {
|
||||||
|
"version": "3.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
|
||||||
|
"integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"wcwidth": {
|
"wcwidth": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||||
|
|||||||
@@ -11,9 +11,12 @@
|
|||||||
"package:ext": "npm run package --prefix ./ext",
|
"package:ext": "npm run package --prefix ./ext",
|
||||||
"test": "node test/driver.js",
|
"test": "node test/driver.js",
|
||||||
"install-manifest": "npm run install-manifest --prefix ./app",
|
"install-manifest": "npm run install-manifest --prefix ./app",
|
||||||
"remove-manifest": "npm run remove-manifest --prefix ./app"
|
"remove-manifest": "npm run remove-manifest --prefix ./app",
|
||||||
|
"lint": "npm run lint:app",
|
||||||
|
"lint:app": "npm run lint --prefix ./app"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/uuid": "^3.4.4",
|
||||||
"fs-extra": "^7.0.1",
|
"fs-extra": "^7.0.1",
|
||||||
"glob": "^7.1.3",
|
"glob": "^7.1.3",
|
||||||
"jasmine-console-reporter": "^3.1.0",
|
"jasmine-console-reporter": "^3.1.0",
|
||||||
@@ -21,6 +24,7 @@
|
|||||||
"selenium-webdriver": "^4.0.0-alpha.1",
|
"selenium-webdriver": "^4.0.0-alpha.1",
|
||||||
"semver": "^5.6.0",
|
"semver": "^5.6.0",
|
||||||
"typescript": "^3.3.3333",
|
"typescript": "^3.3.3333",
|
||||||
|
"uuid": "^3.3.2",
|
||||||
"ws": "^6.1.2"
|
"ws": "^6.1.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user