Research
Security News
Quasar RAT Disguised as an npm Package for Detecting Vulnerabilities in Ethereum Smart Contracts
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
A modular, pipe-able, micro-service framework.
Table of Contents
Why a framework? After building micro-services a wide variety of ways over a number of years, in small organizations and large, I wanted to standardize the approach, and bring together all the lessons learned. Argosy draws inspiration from many sources including a smorgasbord of systems (I've used in other micro-service projects) such as RabbitMQ and Zookeeper, as well as other node libraries including but not limited to dnode, rpc-stream, and seneca.
Like the micro-service model, the Argosy ecosystem consists of many small modules. These components are streams, designed to be connected together via pipes. Extending Argosy is a matter of manipulating the stream.
var http = require('http'),
query = require('querystring'),
argosy = require('argosy')()
// create a service queue of requests for weather
var weatherRequest = argosy.accept({
get: 'weather',
location: argosy.pattern.match.defined
})
// process the requests for weather
weatherRequest.process(function (msg, cb) {
var qs = query.stringify({ q: msg.location, units: msg.units || 'imperial' })
http.get('http://api.openweathermap.org/data/2.5/weather?' + qs, function (res) {
var body = ''
res.on('data', function (data) {
body += data
}).on('end', function () {
cb(null, JSON.parse(body).main)
})
})
})
// use the service
argosy.invoke({ get: 'weather', location: 'Boston,MA' }, function (err, weather) {
console.log(weather.temp + ' degrees (F) in Boston.')
})
// or create a convenience function using invoke.partial
var getWeather = argosy.invoke.partial({ get: 'weather', units: 'metric' })
getWeather({ location: 'Dublin,IE' }, function (err, weather) {
console.log(weather.temp + ' degrees (C) in Dublin.')
})
// or use promises
getWeather({ location: 'London,UK' }).then(function (weather) {
console.log(weather.temp + ' degrees (C) in London.')
})
var http = require('http'),
query = require('querystring').stringify,
request = require('request-promise'),
co = require('co'),
argosy = require('..')()
// create a service queue of requests for weather
var weatherRequest = argosy.accept({
get: 'weather',
location: argosy.pattern.match.defined
})
// process the requests for weather
var weatherUrl = 'http://api.openweathermap.org/data/2.5/weather?'
weatherRequest.process(co.wrap(function* ({ location: q, units = 'imperial' }) {
var weather = yield request.get(weatherUrl + query({ q, units }))
return JSON.parse(weather).main
}))
// we can create a convenience function with invoke.partial
var getWeather = argosy.invoke.partial({ get: 'weather', units: 'metric' })
co(function* () {
// use invoke directly
var boston = yield argosy.invoke({ get: 'weather', location: 'Boston,MA' })
// or use our shiny new convenient function
var dublin = yield getWeather({ location: 'Dublin,IE' })
var london = yield getWeather({ location: 'London,UK' })
console.log(boston.temp + ' degrees (F) in Boston.')
console.log(dublin.temp + ' degrees (C) in Dublin.')
console.log(london.temp + ' degrees (C) in London.\n')
})
Note: If your runtime doesn't offer generators or promises, you can still run the above example from the example directory via babel. Just do: npm i -g babel && babel-node example/es6.js
// Create a new Argosy endpoint/stream
var argosy = require('argosy')()
Create a concurrent-queue that will be pushed messages that match the pattern
object provided (see argosy-pattern for details on defining patterns). These messages should be processed and responded to using the process
function of the queue
. Responses will be sent to the requesting Argosy endpoint.
It is advised not to match the key argosy
as this is reserved for internal use.
Process messages. See concurrent-queue for more information. The processor function func
has a signature of msg [, cb]
. The callback cb
if provided should be executed with any applicable return value or error object (as 1st argument) for the invoking client, once the request has been completed. Alternatively, a promise may be returned from the processor function func
, and its resolved value or rejected error will be returned to the invoking client.
Invoke a service which implements the msg
object pattern. Upon completion, the callback cb
, if supplied, will be called with the result or error. The argosy.invoke
function also returns a promise which will resolve or reject appropriately. If the msg
matches one of the patterns implemented by the argosy
endpoint performing the invoke
, then the invoke
request will be handled locally by the the Argosy endpoint invoke
was called from, otherwise the invoke
request will be written to the stream's output, and the stream's input will be monitored for a response.
Return a function that represents a partial invocation. The function returned has the same signature as argosy.invoke
, but when called, the msg
object parameter will be merged with the partialMsg
object parameter provided at the time the function was created. Otherwise, the generated function behaves identically to argosy.invoke
.
Accepts an array of strings, these strings are subscription topics. Valid subscription topics are:
services
- Be notified when the remote argosy endpoint adds a service. All existing remote services will be sent immediately.Also accepts an optional error-first callback, which will be invoked after the remote argosy endpoint has sent all existing services.
This function returns a promise.
Argosy exposes the following eventuates:
Produces messages when any service is added to the argosy
endpoint (local or remote). The structure of the message is:
{
remote: true|false,
provider: {
id: uuid
},
pattern: argosyPattern
}
Where argosyPattern
is an argosy.pattern
Produces messages when a local service is added to the argosy
endpoint. The structure of the message is:
remote: false,
provider: {
id: uuid
},
pattern: argosyPattern
Where argosyPattern
is an argosy.pattern
Produces messages when a remote service is added to the argosy
endpoint. The structure of the message is:
remote: true,
provider: {
id: uuid
},
pattern: argosyPattern
Produces messages when a remote service has advertised all subscribed resources to the local argosy
endpoint.
provider: {
id: uuid
},
services: count
Where services
is present only if the remote subscription includes "services".
See also argosy-pattern.
Create an Argosy pattern, given an object containing rules. Each key in the object represents a key that is to be validated in compared message objects. These keys will be tested to have the same literal value, matching regular expression, or to be of a given type using the matching system described below. Nested keys may be matched using the dot notation. For example, {'message.count':1}
equates to {message: {count: 1}}
.
Returns true of the given object matches the pattern, or false otherwise.
Argosy patterns support more than literal values. The values of the pattern keys may be any of the following in addition to literal values:
argosy.pattern.match.number
- matches any numberargosy.pattern.match.string
- matches any stringargosy.pattern.match.bool
- matches true
or false
argosy.pattern.match.array
- matches any arrayargosy.pattern.match.object
- matches any truthy objectargosy.pattern.match.defined
- matches anything other than undefined
argosy.pattern.match.undefined
- matches undefined
or missing keyOne Argosy endpoint may be connected to another via pipes.
var argosy = require('argosy'),
service1 = argosy(),
service2 = argosy()
service1.pipe(service2).pipe(service)
This will create a duplex connection between the two Argosy endpoints, and allow both to invoke implemented services via the other. For example:
service1.accept({ get: 'random number' }).process(function (msg, cb) {
// do something interesting
})
service2.accept({ get: 'random letter' }).process(function (msg, cb) {
// do something interesting
})
service1.invoke({ get: 'random letter' }, function (err, letter) {
// this works
})
service2.invoke({ get: 'random number' }, function (err, number) {
// so does this
})
npm test [--dot | --spec] [--phantom] [--grep=pattern]
Specifying --dot
or --spec
will change the output from the default TAP style.
Specifying --phantom
will cause the tests to run in the headless phantom browser instead of node.
Specifying --grep
will only run the test files that match the given pattern.
npm run browser-test
This will run the tests in all browsers (specified in .zuul.yml). Be sure to educate zuul first.
npm run coverage [--html]
This will output a textual coverage report. Including --html
will also open
an HTML coverage report in the default browser.
FAQs
A modular, pipable, micro-service framework
The npm package argosy receives a total of 1 weekly downloads. As such, argosy popularity was classified as not popular.
We found that argosy 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
Security News
Socket researchers uncover a malicious npm package posing as a tool for detecting vulnerabilities in Etherium smart contracts.
Security News
Research
A supply chain attack on Rspack's npm packages injected cryptomining malware, potentially impacting thousands of developers.
Research
Security News
Socket researchers discovered a malware campaign on npm delivering the Skuld infostealer via typosquatted packages, exposing sensitive data.