@basmilius/apple-companion-link 0.0.77 → 0.0.79
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1 -1
- package/dist/socket.d.ts +2 -11
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var f={Up:1,Down:2,Left:3,Right:4,Menu:5,Select:6,Home:7,VolumeUp:8,VolumeDown:9,Siri:10,Screensaver:11,Sleep:12,Wake:13,PlayPause:14,ChannelIncrement:15,ChannelDecrement:16,Guide:17,PageUp:18,PageDown:19},
|
|
1
|
+
var f={Up:1,Down:2,Left:3,Right:4,Menu:5,Select:6,Home:7,VolumeUp:8,VolumeDown:9,Siri:10,Screensaver:11,Sleep:12,Wake:13,PlayPause:14,ChannelIncrement:15,ChannelDecrement:16,Guide:17,PageUp:18,PageDown:19},_={Play:1,Pause:2,NextTrack:3,PreviousTrack:4,GetVolume:5,SetVolume:6,SkipBy:7,FastForwardBegin:8,FastForwardEnd:9,RewindBegin:10,RewindEnd:11,GetCaptionSettings:12,SetCaptionSettings:13};function P(e){switch(e){case 1:return"asleep";case 2:return"screensaver";case 3:return"awake";case 4:return"idle";default:return"unknown"}}import{randomInt as E}from"node:crypto";import{reporter as R,waitFor as B}from"@basmilius/apple-common";import{OPack as b,Plist as K}from"@basmilius/apple-encoding";var n={Unknown:0,Noop:1,PS_Start:3,PS_Next:4,PV_Start:5,PV_Next:6,U_OPACK:7,E_OPACK:8,P_OPACK:9,PA_Request:10,PA_Response:11,SessionStartRequest:16,SessionStartResponse:17,SessionData:18,FamilyIdentityRequest:32,FamilyIdentityResponse:33,FamilyIdentityUpdate:34},s={Event:1,Request:2,Response:3},S=[n.PS_Start,n.PS_Next,n.PV_Start,n.PV_Next,n.U_OPACK,n.E_OPACK,n.P_OPACK],x=[n.PS_Start,n.PS_Next,n.PV_Start,n.PV_Next];class u{get socket(){return this.#t.socket}#t;constructor(e){this.#t=e}async fetchMediaControlStatus(){await this.socket.exchange(n.E_OPACK,{_i:"FetchMediaControlStatus",_t:s.Request,_c:{}})}async fetchNowPlayingInfo(){await this.socket.exchange(n.E_OPACK,{_i:"FetchCurrentNowPlayingInfoEvent",_t:s.Request,_c:{}})}async fetchSupportedActions(){await this.socket.exchange(n.E_OPACK,{_i:"FetchSupportedActionsEvent",_t:s.Request,_c:{}})}async getAttentionState(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"FetchAttentionState",_t:s.Request,_c:{}}),{_c:t}=m(e);return P(t.state)}async getLaunchableApps(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"FetchLaunchableApplicationsEvent",_t:s.Request,_c:{}}),{_c:t}=m(e);return Object.entries(t).map(([r,o])=>({bundleId:r,name:o}))}async getSiriRemoteInfo(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"FetchSiriRemoteInfo",_t:s.Request,_c:{}});return K.parse(Buffer.from(e._c.SiriRemoteInfoKey).buffer)}async getUserAccounts(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"FetchUserAccountsEvent",_t:s.Request,_c:{}}),{_c:t}=m(e);return Object.entries(t).map(([r,o])=>({accountId:r,name:o}))}async hidCommand(e,t=!1){await this.socket.exchange(n.E_OPACK,{_i:"_hidC",_t:s.Request,_c:{_hBtS:t?1:2,_hidC:f[e]}})}async launchApp(e){await this.socket.exchange(n.E_OPACK,{_i:"_launchApp",_t:s.Request,_c:{_bundleID:e}})}async launchUrl(e){await this.socket.exchange(n.E_OPACK,{_i:"_launchApp",_t:s.Request,_c:{_urlS:e}})}async mediaControlCommand(e,t){let[,r]=await this.socket.exchange(n.E_OPACK,{_i:"_mcc",_t:s.Request,_c:{_mcc:_[e],...t||{}}});return m(r)}async pressButton(e,t="SingleTap",r=500){switch(t){case"DoubleTap":await this.hidCommand(e,!0),await this.hidCommand(e,!1),await this.hidCommand(e,!0),await this.hidCommand(e,!1);break;case"Hold":await this.hidCommand(e,!0),await B(r),await this.hidCommand(e,!1);break;case"SingleTap":await this.hidCommand(e,!0),await this.hidCommand(e,!1);break}}async switchUserAccount(e){await this.socket.exchange(n.E_OPACK,{_i:"SwitchUserAccountEvent",_t:s.Request,_c:{SwitchAccountID:e}})}async _subscribe(e,t){this.socket.on(e,t),await this.socket.send(n.E_OPACK,{_i:"_interest",_t:s.Event,_c:{_regEvents:[e]}})}async _unsubscribe(e,t){if(t)this.socket.off(e,t);await this.socket.send(n.E_OPACK,{_i:"_interest",_t:s.Event,_c:{_deregEvents:[e]}})}async _sessionStart(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"_sessionStart",_t:s.Request,_c:{_srvT:"com.apple.tvremoteservices",_sid:E(0,4294967295)}});return m(e)}async _systemInfo(e){let[,t]=await this.socket.exchange(n.E_OPACK,{_i:"_systemInfo",_t:s.Request,_c:{_bf:0,_cf:512,_clFl:128,_i:"cafecafecafe",_idsID:e.toString(),_pubID:"FF:70:79:61:74:76",_sf:256,_sv:"170.18",model:"iPhone10,6",name:"Bas Companion Link"}});return m(t)}async _touchStart(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"_touchStart",_t:s.Request,_c:{_height:b.float(1000),_tFl:0,_width:b.float(1000)}});return m(e)}async _tvrcSessionStart(){let[,e]=await this.socket.exchange(n.E_OPACK,{_i:"TVRCSessionStart",_t:s.Request,_btHP:!1,_inUseProc:"tvremoted",_c:{}});return m(e)}}function m(e){if(typeof e==="object")return e;throw R.error("Expected an object.",{obj:e}),Error("Expected an object.")}import{AccessoryPair as L}from"@basmilius/apple-common";class y{get internal(){return this.#t}get socket(){return this.#o.socket}#t;#o;constructor(e){this.#t=new L(this.#e.bind(this)),this.#o=e}async start(){await this.#t.start()}async pin(e){return this.#t.pin(e)}async transient(){return this.#t.transient()}async#e(e,t){let r=e==="m1"?n.PS_Start:n.PS_Next,[,o]=await this.socket.exchange(r,{_pd:t,_pwTy:1});if(typeof o!=="object"||o===null)throw Error("Invalid response from receiver.");return o._pd}}import{randomInt as T}from"node:crypto";import{Chacha20 as g,ENCRYPTION as O,EncryptionAwareConnection as F,reporter as p}from"@basmilius/apple-common";import{OPack as w}from"@basmilius/apple-encoding";var C=4;class d extends F{get#t(){return this[O]}#o={};#e=Buffer.alloc(0);#n;constructor(e,t){super(e,t);this.#n=T(0,65536),this.onData=this.onData.bind(this),this.on("data",this.onData)}async exchange(e,t){let r=this.#n;return new Promise((o,i)=>{if(x.includes(e))this.#o[-1]=o;else this.#o[r]=o;this.send(e,t).catch(i)})}async send(e,t){let r=this.#n++;t._x??=w.sizedInt(r,8);let o=Buffer.from(w.encode(t)),i=o.byteLength;if(this.isEncrypted&&i>0)i+=g.CHACHA20_AUTH_TAG_LENGTH;let c=Buffer.allocUnsafe(4);c.writeUint8(e,0),c.writeUintBE(i,1,3);let a;if(this.isEncrypted){let h=Buffer.alloc(12);h.writeBigUInt64LE(BigInt(this.#t.writeCount++),0);let k=g.encrypt(this.#t.writeKey,h,c,o);a=Buffer.concat([c,k.ciphertext,k.authTag])}else a=Buffer.concat([c,o]);return p.raw("Sending data frame...",this.isEncrypted,Buffer.from(a).toString("hex"),t),await this.write(a)}async onData(e){p.raw("Received data frame",e.toString("hex")),this.#e=Buffer.concat([this.#e,e]);while(this.#e.byteLength>=C){let t=this.#e.subarray(0,C),r=t.readUintBE(1,3),o=C+r;if(this.#e.byteLength<o){p.warn(`Not enough data yet, waiting on the next frame.. needed=${o} available=${this.#e.byteLength} receivedLength=${e.byteLength}`);return}p.raw(`Frame found length=${o} availableLength=${this.#e.byteLength} receivedLength=${e.byteLength}`);let i=Buffer.from(this.#e.subarray(0,o));this.#e=this.#e.subarray(o),p.raw(`Handle frame, ${this.#e.byteLength} bytes left...`);let a=(await this.#r(i)).subarray(4,o);await this.#s(t,a)}}async#r(e){if(!this.isEncrypted)return e;let t=e.subarray(0,4),r=t.readUintBE(1,3),o=e.subarray(4,4+r),i=o.subarray(o.byteLength-16),c=o.subarray(0,o.byteLength-16),a=Buffer.alloc(12);a.writeBigUint64LE(BigInt(this.#t.readCount++),0);let h=g.decrypt(this.#t.readKey,a,t,c,i);return Buffer.concat([t,h,i])}async#s(e,t){let r=e.readInt8();if(!S.includes(r)){p.warn("Packet not handled, no opack frame.");return}if(t=w.decode(t),p.raw("Decoded OPACK",{header:e,payload:t}),"_x"in t){let o=t._x;if(o in this.#o)(this.#o[o]??null)?.([e,t]),delete this.#o[o];else if("_i"in t)this.emit(t._i,t._c);else{let i=t._c,c=Object.keys(i).map((a)=>a.substring(0,-3));for(let a of c)this.emit(a,i[a])}}else if(this.#o[-1])(this.#o[-1]??null)?.([e,t]),delete this.#o[-1];else p.warn("No handler for message",[e,t])}}import{AccessoryVerify as I,hkdf as v}from"@basmilius/apple-common";class l{get socket(){return this.#o.socket}#t;#o;constructor(e){this.#t=new I(this.#e.bind(this)),this.#o=e}async start(e){let t=await this.#t.start(e),r=v({hash:"sha512",key:t.sharedSecret,length:32,salt:Buffer.alloc(0),info:Buffer.from("ServerEncrypt-main")}),o=v({hash:"sha512",key:t.sharedSecret,length:32,salt:Buffer.alloc(0),info:Buffer.from("ClientEncrypt-main")});return{accessoryToControllerKey:r,controllerToAccessoryKey:o,pairingId:t.pairingId,sharedSecret:t.sharedSecret}}async#e(e,t){let r=e==="m1"?n.PV_Start:n.PV_Next,[,o]=await this.socket.exchange(r,{_pd:t,_auTy:4});if(typeof o!=="object"||o===null)throw Error("Invalid response from receiver.");return o._pd}}class A{get api(){return this.#t}get device(){return this.#o}get socket(){return this.#e}get pairing(){return this.#n}get verify(){return this.#r}#t;#o;#e;#n;#r;constructor(e){this.#o=e,this.#e=new d(e.address,e.service.port),this.#t=new u(this),this.#n=new y(this),this.#r=new l(this)}async connect(){await this.#e.connect()}async disconnect(){await this.#e.disconnect()}}export{P as convertAttentionState,_ as MediaControlCommand,f as HidCommand,A as CompanionLink};
|
package/dist/socket.d.ts
CHANGED
|
@@ -1,17 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export default class CompanionLinkSocket extends
|
|
1
|
+
import { EncryptionAwareConnection } from "@basmilius/apple-common";
|
|
2
|
+
export default class CompanionLinkSocket extends EncryptionAwareConnection<Record<string, [unknown]>> {
|
|
3
3
|
#private;
|
|
4
|
-
get isConnected(): boolean;
|
|
5
|
-
get isEncrypted(): boolean;
|
|
6
4
|
constructor(address: string, port: number);
|
|
7
|
-
connect(): Promise<void>;
|
|
8
|
-
disconnect(): Promise<void>;
|
|
9
|
-
enableEncryption(readKey: Buffer, writeKey: Buffer): Promise<void>;
|
|
10
5
|
exchange(type: number, obj: Record<string, unknown>): Promise<[number, unknown]>;
|
|
11
6
|
send(type: number, obj: Record<string, unknown>): Promise<void>;
|
|
12
|
-
onClose(): Promise<void>;
|
|
13
|
-
onConnect(): Promise<void>;
|
|
14
7
|
onData(buffer: Buffer): Promise<void>;
|
|
15
|
-
onEnd(): Promise<void>;
|
|
16
|
-
onError(err: Error): Promise<void>;
|
|
17
8
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@basmilius/apple-companion-link",
|
|
3
3
|
"description": "Implementation of Apple's Companion Link in Node.js.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.79",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": {
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
}
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@basmilius/apple-common": "0.0.
|
|
44
|
-
"@basmilius/apple-encoding": "0.0.
|
|
43
|
+
"@basmilius/apple-common": "0.0.79",
|
|
44
|
+
"@basmilius/apple-encoding": "0.0.79"
|
|
45
45
|
},
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@basmilius/tools": "^2.23.0",
|