Comparing version 0.1.9 to 0.1.10
@@ -67,12 +67,12 @@ var EventEmitter = require('events').EventEmitter; | ||
'recv message: protocolVersion=%s sourceId=%s destinationId=%s namespace=%s data=%s', | ||
message.protocol_version, | ||
message.source_id, | ||
message.destination_id, | ||
message.protocolVersion, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? util.inspect(message.payload_binary) | ||
: message.payload_utf8 | ||
(message.payloadType === 1) // BINARY | ||
? util.inspect(message.payloadBinary) | ||
: message.payloadUtf8 | ||
); | ||
if(message.protocol_version !== 0) { // CASTV2_1_0 | ||
self.emit('error', new Error('Unsupported protocol version: ' + message.protocol_version)); | ||
if(message.protocolVersion !== 0) { // CASTV2_1_0 | ||
self.emit('error', new Error('Unsupported protocol version: ' + message.protocolVersion)); | ||
self.close(); | ||
@@ -83,9 +83,9 @@ return; | ||
self.emit('message', | ||
message.source_id, | ||
message.destination_id, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? message.payload_binary | ||
: message.payload_utf8 | ||
); | ||
(message.payloadType === 1) // BINARY | ||
? message.payloadBinary | ||
: message.payloadUtf8 | ||
); | ||
} | ||
@@ -104,5 +104,5 @@ | ||
var message = { | ||
protocol_version: 0, // CASTV2_1_0 | ||
source_id: sourceId, | ||
destination_id: destinationId, | ||
protocolVersion: 0, // CASTV2_1_0 | ||
sourceId: sourceId, | ||
destinationId: destinationId, | ||
namespace: namespace | ||
@@ -112,7 +112,7 @@ }; | ||
if(Buffer.isBuffer(data)) { | ||
message.payload_type = 1 // BINARY; | ||
message.payload_binary = data; | ||
message.payloadType = 1 // BINARY; | ||
message.payloadBinary = data; | ||
} else { | ||
message.payload_type = 0 // STRING; | ||
message.payload_utf8 = data; | ||
message.payloadType = 0 // STRING; | ||
message.payloadUtf8 = data; | ||
} | ||
@@ -122,9 +122,9 @@ | ||
'send message: protocolVersion=%s sourceId=%s destinationId=%s namespace=%s data=%s', | ||
message.protocol_version, | ||
message.source_id, | ||
message.destination_id, | ||
message.protocolVersion, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? util.inspect(message.payload_binary) | ||
: message.payload_utf8 | ||
(message.payloadType === 1) // BINARY | ||
? util.inspect(message.payloadBinary) | ||
: message.payloadUtf8 | ||
); | ||
@@ -140,2 +140,2 @@ | ||
module.exports = Client; | ||
module.exports = Client; |
var fs = require('fs'); | ||
var ProtoBuf = require("protobufjs"); | ||
var protobuf = require("protobufjs"); | ||
var builder = ProtoBuf.loadProtoFile(__dirname + "/cast_channel.proto"); | ||
var extensions = builder.build('extensions.api.cast_channel'); | ||
var builder = protobuf.load(__dirname + "/cast_channel.proto", onLoad); | ||
var messages = [ | ||
'CastMessage', | ||
'AuthChallenge', | ||
'AuthResponse', | ||
'AuthError', | ||
'CastMessage', | ||
'AuthChallenge', | ||
'AuthResponse', | ||
'AuthError', | ||
'DeviceAuthMessage' | ||
]; | ||
var extensions = []; | ||
function onLoad(err, root) { | ||
if (err) throw err; | ||
messages.forEach(function(message) { | ||
extensions[message] = | ||
root.lookupType(`extensions.api.cast_channel.${message}`); | ||
}); | ||
} | ||
messages.forEach(function(message) { | ||
module.exports[message] = { | ||
serialize: function(data) { | ||
var msg = new extensions[message](data); | ||
return msg.encode().toBuffer(); | ||
if (!extensions[message]) { | ||
throw new Error('extension not loaded yet'); | ||
} | ||
var Message = extensions[message]; | ||
return Message.encode(data).finish(); | ||
}, | ||
parse: function(data) { | ||
return extensions[message].decode(data); | ||
if (!extensions[message]) { | ||
throw new Error('extension not loaded yet'); | ||
} | ||
var Message = extensions[message]; | ||
return Message.decode(data); | ||
} | ||
}; | ||
}); | ||
}); |
@@ -54,12 +54,12 @@ var EventEmitter = require('events').EventEmitter; | ||
clientId, | ||
message.protocol_version, | ||
message.source_id, | ||
message.destination_id, | ||
message.protocolVersion, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? util.inspect(message.payload_binary) | ||
: message.payload_utf8 | ||
(message.payloadType === 1) // BINARY | ||
? util.inspect(message.payloadBinary) | ||
: message.payloadUtf8 | ||
); | ||
if(message.protocol_version !== 0) { // CASTV2_1_0 | ||
if(message.protocolVersion !== 0) { // CASTV2_1_0 | ||
debug('client error: clientId=%s unsupported protocol version (%s)', clientId, message.protocolVersion); | ||
@@ -73,9 +73,9 @@ var socket = self.clients[clientId].socket; | ||
clientId, | ||
message.source_id, | ||
message.destination_id, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? message.payload_binary | ||
: message.payload_utf8 | ||
); | ||
(message.payloadType === 1) // BINARY | ||
? message.payloadBinary | ||
: message.payloadUtf8 | ||
); | ||
} | ||
@@ -118,5 +118,5 @@ | ||
var message = { | ||
protocol_version: 0, // CASTV2_1_0 | ||
source_id: sourceId, | ||
destination_id: destinationId, | ||
protocolVersion: 0, // CASTV2_1_0 | ||
sourceId: sourceId, | ||
destinationId: destinationId, | ||
namespace: namespace | ||
@@ -126,7 +126,7 @@ }; | ||
if(Buffer.isBuffer(data)) { | ||
message.payload_type = 1 // BINARY; | ||
message.payload_binary = data; | ||
message.payloadType = 1 // BINARY; | ||
message.payloadBinary = data; | ||
} else { | ||
message.payload_type = 0 // STRING; | ||
message.payload_utf8 = data; | ||
message.payloadType = 0 // STRING; | ||
message.payloadUtf8 = data; | ||
} | ||
@@ -137,9 +137,9 @@ | ||
clientId, | ||
message.protocol_version, | ||
message.source_id, | ||
message.destination_id, | ||
message.protocolVersion, | ||
message.sourceId, | ||
message.destinationId, | ||
message.namespace, | ||
(message.payload_type === 1) // BINARY | ||
? util.inspect(message.payload_binary) | ||
: message.payload_utf8 | ||
(message.payloadType === 1) // BINARY | ||
? util.inspect(message.payloadBinary) | ||
: message.payloadUtf8 | ||
); | ||
@@ -156,2 +156,2 @@ | ||
module.exports = Server; | ||
module.exports = Server; |
{ | ||
"name": "castv2", | ||
"version": "0.1.9", | ||
"version": "0.1.10", | ||
"description": "An implementation of the Chromecast CASTV2 protocol", | ||
@@ -9,7 +9,7 @@ "author": "thibauts", | ||
"dependencies": { | ||
"debug": "^2.2.0", | ||
"protobufjs": "^3.2.2" | ||
"debug": "^4.1.1", | ||
"protobufjs": "^6.8.8" | ||
}, | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1" | ||
"test": "echo \"Error: no test specified\" && exit 0" | ||
}, | ||
@@ -16,0 +16,0 @@ "repository": { |
@@ -10,3 +10,3 @@ castv2 | ||
This module is an implementation of the Chromecast CASTV2 protocol over TLS. The internet is very scarse on information about the new Chromecast protocol so big props go to [github.com/vincentbernat](https://github.com/vincentbernat) and his [nodecastor](https://github.com/vincentbernat/nodecastor) module that helped me start off on the right foot and save a good deal of time in my research. | ||
This module is an implementation of the Chromecast CASTV2 protocol over TLS. The internet is very sparse on information about the new Chromecast protocol so big props go to [github.com/vincentbernat](https://github.com/vincentbernat) and his [nodecastor](https://github.com/vincentbernat/nodecastor) module that helped me start off on the right foot and save a good deal of time in my research. | ||
@@ -85,3 +85,3 @@ The module provides both a `Client` and a `Server` implementation of the low-level protocol. The server is (sadly) pretty useless because device authentication gets in the way for now (and maybe for good). The client still allows you to connect and exchange messages with a Chromecast dongle without any restriction. | ||
This is an attempt at documenting the low-level protocol. I hope it will give sender-app makers a clearer picture of what is happening behind the curtain, and give the others ideas about how this kind of protocol can be implemented. The information presented here has been collated from various internet sources (mainly exemple code and other attempts to implement the protocol) and my own trial and error. Correct me as needed as I may have gotten concepts or namings wrong. | ||
This is an attempt at documenting the low-level protocol. I hope it will give sender-app makers a clearer picture of what is happening behind the curtain, and give the others ideas about how this kind of protocol can be implemented. The information presented here has been collated from various internet sources (mainly example code and other attempts to implement the protocol) and my own trial and error. Correct me as needed as I may have gotten concepts or namings wrong. | ||
@@ -144,3 +144,3 @@ ### The TLS / Protocol Buffers layer | ||
Before being able to echange messages with a receiver (be it an *application* or the *platform*), a sender must establish a *virtual connection* with it. This is accomplished through the `urn:x-cast:com.google.cast.tp.connection` namespace / protocol. This has the effect of both allowing the sender to send messages to the receiver, and of subscribing the sender to the receiver's broadcasts (eg. status updates). | ||
Before being able to exchange messages with a receiver (be it an *application* or the *platform*), a sender must establish a *virtual connection* with it. This is accomplished through the `urn:x-cast:com.google.cast.tp.connection` namespace / protocol. This has the effect of both allowing the sender to send messages to the receiver, and of subscribing the sender to the receiver's broadcasts (eg. status updates). | ||
@@ -160,3 +160,3 @@ The protocol is JSON encoded and the semantics are pretty simple : | ||
Connections are kept alive through the `urn:x-cast:com.google.cast.tp.heartbeat` namespace / protocol. At regular intervals the sender must send a `PING` message that will get answered by a `PONG`. The protocol is JSON encoded. | ||
Connections are kept alive through the `urn:x-cast:com.google.cast.tp.heartbeat` namespace / protocol. At regular intervals, the sender must send a `PING` message that will get answered by a `PONG`. The protocol is JSON encoded. | ||
@@ -174,3 +174,3 @@ | **Message payload** | **Description** | ||
First the sender sends a *challenge* message to the platform receiver `receiver-0` which responds by either a *response* message containing a signature, certificate and a variable number of certificate authority certificates that the sent certificate is verified against or an *error* message. These 3 payloads are protocol buffers encoded and described in `cast_channel.proto` as follows : | ||
First, the sender sends a *challenge* message to the platform receiver `receiver-0` which responds by either a *response* message containing a signature, certificate and a variable number of certificate authority certificates that the sent certificate is verified against or an *error* message. These 3 payloads are protocol buffers encoded and described in `cast_channel.proto` as follows : | ||
@@ -206,5 +206,5 @@ ```protobuf | ||
The platform receiver `receiver-0` implements the `urn:x-cast:com.google.cast.receiver` namespace / protocol which provides an interface to *launch*, *stop*, and *query the status* of running applications. `receiver-0` also broadcast status messages on this namespace when other senders launch, stop, or affect the status of running apps. It also allows to check app for availability. | ||
The platform receiver `receiver-0` implements the `urn:x-cast:com.google.cast.receiver` namespace / protocol which provides an interface to *launch*, *stop*, and *query the status* of running applications. `receiver-0` also broadcast status messages on this namespace when other senders launch, stop, or affect the status of running apps. It also allows checking the app for availability. | ||
The protocol is JSON encoded and is request / response based. Requests include a `type` field containing the type of the request, namely `LAUNCH`, `STOP`, `GET_STATUS` and `GET_APP_AVAILABILITY`, and a `requestId` field that will be reflected in the receiver's response and allows the sender to pair request and responses. `requestId` is not shown in the table below but must be present in every request. In the wild it is an initially random integer that gets incremented for each subsequent request. | ||
The protocol is JSON encoded and is request / response based. Requests include a `type` field containing the type of the request, namely `LAUNCH`, `STOP`, `GET_STATUS` and `GET_APP_AVAILABILITY`, and a `requestId` field that will be reflected in the receiver's response and allows the sender to pair request and responses. `requestId` is not shown in the table below but must be present in every request. In the wild, it is an initially random integer that gets incremented for each subsequent request. | ||
@@ -249,3 +249,3 @@ | **Message payload** | **Description** | ||
Another important field here is `transportId` as it is the destinationId to be used to communicate with the app. Note that the app being a receiver like any other you must issue it a `CONNECT` message through the `urn:x-cast:com.google.cast.tp.connection` procotol before being able to send messages. In this case this will have the side effect of subscribing you to media updates (on the media channel) of this *Default Media Player* session. | ||
Another important field here is `transportId` as it is the destinationId to be used to communicate with the app. Note that the app being a receiver like any other you must issue it a `CONNECT` message through the `urn:x-cast:com.google.cast.tp.connection` protocol before being able to send messages. In this case, this will have the side effect of subscribing you to media updates (on the media channel) of this *Default Media Player* session. | ||
@@ -252,0 +252,0 @@ You can join an existing session (launched by another sender) by issuing the same `CONNECT` message. |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No tests
QualityPackage does not have any tests. This is a strong signal of a poorly maintained or low quality package.
Found 1 instance in 1 package
33436
359
15
3
+ Added@protobufjs/aspromise@1.1.2(transitive)
+ Added@protobufjs/base64@1.1.2(transitive)
+ Added@protobufjs/codegen@2.0.4(transitive)
+ Added@protobufjs/eventemitter@1.1.0(transitive)
+ Added@protobufjs/fetch@1.1.0(transitive)
+ Added@protobufjs/float@1.0.2(transitive)
+ Added@protobufjs/inquire@1.1.0(transitive)
+ Added@protobufjs/path@1.1.2(transitive)
+ Added@protobufjs/pool@1.1.0(transitive)
+ Added@protobufjs/utf8@1.1.0(transitive)
+ Added@types/long@4.0.2(transitive)
+ Added@types/node@22.5.5(transitive)
+ Addeddebug@4.3.7(transitive)
+ Addedlong@4.0.0(transitive)
+ Addedms@2.1.3(transitive)
+ Addedprotobufjs@6.11.4(transitive)
+ Addedundici-types@6.19.8(transitive)
- Removedascli@0.3.0(transitive)
- Removedbufferview@1.0.1(transitive)
- Removedbytebuffer@3.5.5(transitive)
- Removedcolour@0.7.1(transitive)
- Removeddebug@2.6.9(transitive)
- Removedlong@2.4.0(transitive)
- Removedms@2.0.0(transitive)
- Removedoptjs@3.2.2(transitive)
- Removedprotobufjs@3.8.2(transitive)
Updateddebug@^4.1.1
Updatedprotobufjs@^6.8.8