
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
rpep.js
This is a javascript implementation of the Remote Procedure and Event Protocol (RPEP) for node.js and the browser. RPEP is a simple, light-weight protocol for request-response and stream-event style communication between peers.
var rpep = require("rpep")
var websockets = require("rpep-websockets/ws.node") // For node.js
var msgpack = require("rpep-msgpack")
// server
var server = rpep(websockets(), msgpack)
server.respond('x', function(request) {
return request+1
})
server.stream('y', function(emitter) {
this.connectionInfo // Will hold "Some object". This can be used to pass connection state between command listeners.
emitter.emit('hi')
emitter.on('end', function() {
emitter.emit("end") // end the stream (but not the connection)
this.close() // close the connection
}.bind(this))
})
server.listen(80, function(request) {
var conn = request.accept()
})
// client (usually on a different machine ; )
var client = rpep(websockets(), msgpack)
client.connect('yourhost.me', 80).then(function(conn) {
conn.connectionInfo = "Some object"
conn.request('x', 5).then(function(result) {
console.log(result) // result will be 6
})
conn.streamConnect('y').then(function(emitter) {
emitter.on('hi', function() {
emitter.emit('hello')
emitter.emit('end')
})
})
})
yarn add rpep
Accessing rpep:
// node.js
var rpep = require('rpep')
// amd
require.config({paths: {'rpep': '../dist/rpep.umd.js'}})
require(['rpep'], function(rpep) { /* your code */ })
// global variable
<script src="rpep.umd.js"></script>
rpep; // rpep.umd.js can define rpep globally if you really
// want to shun module-based design
Using rpep:
var peer = rpep(transport, serialization, rpepOptions)
- Creates a new rpep Peer.
transport
- An rpep transport object (described below in the Transports section)serialization
- An rpep serialization object (described below in the Serializations section)rpepOptions
- (Default: {}
) An object with the following properties
maxSendSize
- (Default: no limit) The maximum byte-length a sent message can be.maxReceiveSize
- (Default: no limit) The maximum byte-length a received message can be.maxId
- (Default: 2^53
) The maximum ID to use for request and stream commands, as well as stream order IDs.closeTimeout
- (Default: 30,000 ms
) The number of milliseconds to wait for outstanding requests and streams to complete before closing the connection. If the timeout is reached, an 'error' is emitted containing information about what requests and streams were still pending.sendCommandErrorInfo
- (Default:true
) If true
, errors will automatically be sent to the other Peer if their command is unparsable, and the first part of the command will be sent with an "invalidMessage" error. If false
, the error will be ignored (but handleable via rawHandle
or preHandle
, depending on the case).rpep.PeerError
- A custom Error
object that can be thrown from a respond
handler in order to create an error response (which should throw an error for the peer making the request).
peer.connect(arguments...)
- Connects to a Peer. Returns a promise that resolves to an Rpep Connection Object if it successfully connects, or resolves to an error if it couldn't connect. The arguments
are transport-specific.
peer.listen(arguments..., requestHandler)
- Listens for connections. Returns a promise that resolves successfully when it begins listening, or resolves to an error if it couldn't begin listening.
arguments...
(other than the last one) are transport-specific.requestHandler(request)
- A function called when a connection request comes through. The request
can be accept
ed to complete the connection, or reject
ed to reject the connection. See the Rpep Request Object section for details about request
.peer.close()
- Closes the listener. If the server is already closed, this is a no-op.
peer.receive(command, handler)
- Creates a fire-and-forget receive handler
for the given command
.
command
- A string command name.handler(arguments...)
- The function called when a fire-and-forget message is received. The call will have a number of arguments
depending on how many the message contains.peer.respond(command, handler)
- Creates a request-response handler
for the given command
.
command
- A string command name.handler(arguments..., ID)
- The function called when a request-response message is received. If a normal value is returned from the handler, that value will be returned as the result to the other Peer. If an rpep.PeerError
is thrown from the handler, an error will be returned as an error-result to the other Peer. A promise can also be returned that can be resolved to a normal value or rpep.PeerError
and those are handled the same way. If an exception that isn't a PeerError
is thrown from the handler, the request will be responded to with an "unexpectedPeerError"
error response.
arguments...
- The call will have a number of arguments
depending on how many the message contains.ID
- The last parameter will contain the ID
number of the message.peer.stream(command, handler)
- Creates a full-duplex stream handler
for the given command
.
command
- A string command name.handler(stream, arguments..., ID)
- The function called when a stream initialization message is received.
stream
- A DuplexEventEmitter
object used to send and receive events. See the DuplexEventEmitter
section for more information.arguments...
- The call will have a number of arguments
depending on how many the message contains.ID
- The last parameter will contain the ID
number of the message.peer.default(handler)
- Creates a handler
that is called if a well-formed command is received but there isn't a receive
, respond
, or stream
handler set up for that command.
handler(message)
- The callback. The message
is a parsed rpep message (see the RPEP protocol for defails)peer.preHandle(handler)
- Creates a handler
that is called before any receive
, respond
, stream
, or default
handler is called.
handler(message)
- The callback. The message
is a parsed rpep message (see the RPEP protocol for defails). If the handler returns "ignore" the message will not trigger any receive
, respond
, stream
, or default
handler.peer.rawHandle(handler)
- Creates a handler
that is called before the message is parsed by the serialization
(which happens before preHandle
).
handler(rawMessage)
- The callback. The rawMessage
is a unparsed rpep message in whatever format the configured serialization
dictates. If the handler returns "ignore" the message will not trigger any receive
, respond
, stream
, default
, or preHandle
handler.listening
- Emitted when the listener has started listening.
close
- Emitted when the listener has been closed.
error(e)
- An error event is emitted from the connection if there is an error during listening.
An Rpep Connection Object is an EventEmitter2 object that can emit events as well as call connection methods.
Connection Object Properties and Methods:
connectionObject.fire(command, arguments...)
- Sends a fire-and-forget command.
command
- The string command name.arguments...
- A variable number of command arguments. If the command is error
, there must only be one argument that is an object containing a message
property (eg an Error
object) and any other iterable properties will be added as error data properties.connectionObject.request(command, arguments...)
- Sends an RPC-style request. Returns a promise that resolves to the result of the request (either a value or an error).
command
- The string command name.arguments...
- A variable number of request arguments.connectionObject.streamConnect(command, arguments...)
- Sends a command initializing a stream. Returns a DuplexEventEmitter
event stream that is used to send and receive events.
command
- The string command name.arguments...
- A variable number of stream initialization arguments.connectionObject.close()
- Closes the connection.
connectionObject.drop()
- Closes the connection without informing the other Peer. If the transport doesn't support this, this does the same thing as close
.
connectionObject.connection
- The transport connection returned by transport.connection(..)
. This could be used to send raw RPEP messages.
connectionObject.rawConnection
- The raw connection the transport wraps. This allows access to transport-specific connection properties.
Rpep Connection Object Events:
close
- Emitted when the connection has been closed.
error(e)
- An error event is emitted from the connection in the following cases:
rpep.PeerError
is thrown from a respond handlerRpep Connection Object Error codes
unparsableCommand
- Emitted when an unparsable message is received from the remote peer.invalidCommandType
- Emitted when an invalid command is received from the remote peer.invalidStreamMessage
- Emitted when an invalid stream message is received from the remote peer.An rpep request object is passed to the listen
requestHandler
callback. It is used to either accept or reject the connection. It has the following methods and properties:
request.accept(arguments...)
- Accepts the connection and returns an Rpep Connection Object.
request.reject(arguments...)
- Accepts the connection and returns an Rpep Connection Object.
arguments...
- Both methods take any number of transport-specific arguments.request.rawRequest
- The raw request from the transport.
DuplexEventEmitter
A DuplexEventEmitter
is a special event emitter used to both listen for events from a stream and send events across the stream. Note that "error"
and "end"
events have special meanings (see the RPEP protocol for details)
DuplexEventEmitter
is intended to look and act like an EventEmitter2 object object, and so has the following methosd and properties:
stream.emit(event, arguments...)
- Emits an event to the other Peer.
event
- The string event name.arguments...
- A variable number of event arguments.stream.on(event, handler)
- Listens for a particular event
from the other Peer.
handler(eventArguments...)
- A callback that's called when an event is received on this stream.stream.onAny(handler)
- Listens for any event from the other Peer.
handler(event, eventArguments...)
- A callback that's called when an event
is received on this stream.stream.off(event, handler)
- Removes a handler for a particular event.
stream.offAny(handler)
- Removes an offAny
handler.
A serialization is an object describing how to serialize and deserialize messages from the connection. Serializations must be paired with a transport who's messages are in formats the serialization knows how to deserialize. The object should have the following methods:
serialization.serialize(javascriptObject)
- Serializes the javascript object and returns the result (something the transport can process, most likely a string or Buffer).
serialization.deserialize(serializedObject)
- Returns a javascript object reprented by the serializedObject.
require('rpep/serialization/json')
A transport is an object describing how to send and receive messages. The object has the following properties:
transport.connect(connectArguments..., rpepOptions)
- Connects to another peer. Should return a Transport Connection Object.
connectArguments...
- Any number of transport-specific connect parameters passed into peer.connect
.rpepOptions
- The options passed into rpep
when the peer
was created.transport.listen(listenerArguments..., rpepOptions, requestHandler)
- Listens for connections from another peer. Should return a Transport Listener Object.
listenerArguments...
- Any number of transport-specific listen parameters passed into peer.listen
.rpepOptions
- The options passed into rpep
when the peer
was created.requestHandler(transportRequestObject)
- The requestHandler
passed into peer.listen
. On a request, the requestHandler
should be called with a Transport Request Object.This is very similar to Rpep Request Object. It has all the same methods and properties, but the accept
method should return a Transport Connection Object rather than an Rpep Connnection Object
This is a type of object returned by transport.connect()
and a listener's request.accept()
method calls that allows rpep
to interact with the connection. It has the following methods:
transportConnection.send(message)
- Sends a message to the other Peer.
transportConnection.close()
- Closes the connection in a way that actively informs the other Peer about closure.
transportConnection.drop()
- (Optional) Closes the connection without informing the other Peer.
transportConnection.onOpen(callback)
- Calls the callback
when the connection has opened.
transportConnection.onClose(callback)
- (Optional) Calls the callback
when the connection has closed. If an error happens that causes connection closure, the onClose
callback should still be called, or the connection will be assumed to still be open. If not given, a "close" fire-and-forget message will be sent before connection closure if the Peer is a server, and that "close" message will be listened for if its a client Peer.
transportConnection.onMessage(handler)
- Calls handler(message)
when a message is received over the connection.
transportConnection.onError(errback)
- Calls the callback(e)
when a connection error occurs.
This is a type of object returned by transport.listen
that allows rpep
to interact with the listener. It has the following methods:
transportListner.close()
- Closes the listener.
transportListner.onListening(callback)
- Sets up a callback
that is called when the listener begins listening.
transportListner.onClose(callback)
- Sets up a callback
that is called when the listener stops listening. If an error happens that causes the listener to never start listening or stop listening, the onClose
callback
should still be called, or the listener will be assumed to still be open or opening.
transportListner.onError(errback)
- Sets up a callback
that is called when an error happens while listening.
errback(error)
Anything helps:
How to submit pull requests:
npm install
at its rootnode test/test.node
Released under the MIT license: http://opensource.org/licenses/MIT
FAQs
A javascript implementation of the RPEP protocol https://github.com/Tixit/RPEP
We found that rpep demonstrated a not healthy version release cadence and project activity because the last version was released a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.