Skip to content

Commit

Permalink
added /miners and /connections endpoints, and basic auth
Browse files Browse the repository at this point in the history
  • Loading branch information
Juan Cazala committed Dec 3, 2017
1 parent 40ecc50 commit 0ce74ee
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 18 deletions.
21 changes: 19 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,16 @@ based on the [Stratum Mining Protocol](https://en.bitcoin.it/wiki/Stratum_mining

## Stats

You can see your proxy stats (number of miners and connections) by hittings `/stats`, ie:
`https://localhost:8892/stats`.
The proxy provides a few endpoints to see your stats:

* `/stats`: shows the number of miners and connections

* `/miners`: list of all miners, showing id, login and hashes for each one.

* `/connections`: list of connections, showing id, host, port and amount of miners for each one.

If you want to protect these endpoints (recommended) use the `credentials: { user, pass }` option in the proxy
constructor or the `--credentials=username:password` flag for the CLI.

To get more advanced metrcis you will have to
[run the proxy with PM2](https://github.com/cazala/coin-hive-stratum/wiki/Run-with-PM2).
Expand All @@ -77,6 +85,7 @@ Options:
--path Accept connections on a specific path.
--key Path to private key file. Used for HTTPS/WSS.
--cert Path to certificate file. Used for HTTPS/WSS.
--credentials Credentials to access the /stats, /miners and /connections endponts. (usage: --credentials=username:password)
```

## API
Expand Down Expand Up @@ -111,6 +120,14 @@ Options:

* `cert`: path to certificate file (used for https/wss).

* `credentials`: specify credentials for the API endpoints (`/stats`, `/miners`, `/connections`). If credentials are
provided, you will need to use [Basic Auth](https://developer.mozilla.org/en-US/docs/Web/HTTP/Authentication) to
access the endpoints.

* `user`: a username for the API endpoints

* `pass`: a password for the API endpoints.

* `proxy.listen(port [, host])`: launches the server listening on the specified port (and optionally a host).

* `proxy.on(event, callback)`: specify a callback for an event, each event has information about the miner who triggered
Expand Down
12 changes: 12 additions & 0 deletions bin/coin-hive-stratum
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ const options = {
path: argv.path || defaults.path
};

if (argv["credentials"]) {
try {
const split = argv["credentials"].split(":");
options.credentials = {
user: split[0],
pass: split[1]
};
} catch (e) {
console.warn(`invalid credentials: "${argv["credentials"]}", the should be like "user:pass"`);
}
}

if (isHTTPS) {
options.key = fs.readFileSync(key);
options.cert = fs.readFileSync(cert);
Expand Down
3 changes: 2 additions & 1 deletion bin/help
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ Options:
--max-miners-per-connection Set the max amount of miners per TCP connection. When this number is exceded, a new socket is created. By default it's 100.
--path Accept connections on a specific path.
--key Path to private key file. Used for HTTPS/WSS.
--cert Path to certificate file. Used for HTTPS/WSS.
--cert Path to certificate file. Used for HTTPS/WSS.
--credentials Credentials to access the /stats, /miners and /connections endponts. (usage: --credentials=username:password)
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
"type": "git",
"url": "git+https://github.com/cazala/coin-hive-stratum.git"
},
"keywords": ["coinhive", "stratum", "proxy"],
"keywords": [
"coinhive",
"stratum",
"proxy"
],
"author": "",
"license": "MIT",
"bugs": {
Expand All @@ -26,6 +30,7 @@
"dependencies": {
"@types/node": "^8.0.53",
"@types/ws": "^3.2.0",
"basic-auth": "^2.0.0",
"minimist": "^1.2.0",
"moment": "^2.19.1",
"pmx": "^1.5.5",
Expand Down
81 changes: 68 additions & 13 deletions src/Proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
FoundEvent,
JobEvent,
AuthedEvent,
OpenEvent
OpenEvent,
Credentials
} from "src/types";
import { ServerRequest } from "http";

Expand All @@ -36,6 +37,7 @@ export type Options = {
cert: Buffer;
path: string;
server: http.Server | https.Server;
credentials: Credentials;
};

class Proxy extends EventEmitter {
Expand All @@ -55,8 +57,9 @@ class Proxy extends EventEmitter {
cert: Buffer = null;
path: string = null;
server: http.Server | https.Server = null;
credentials: Credentials = null;

constructor(constructorOptions: Options = defaults) {
constructor(constructorOptions: Partial<Options> = defaults) {
super();
let options = Object.assign({}, defaults, constructorOptions) as Options;
this.host = options.host;
Expand All @@ -73,6 +76,7 @@ class Proxy extends EventEmitter {
this.cert = options.cert;
this.path = options.path;
this.server = options.server;
this.credentials = options.credentials;
this.on("error", () => {
/* prevent unhandled error events from stopping the proxy */
});
Expand All @@ -83,15 +87,46 @@ class Proxy extends EventEmitter {
const isHTTPS = !!(this.key && this.cert);
if (!this.server) {
const stats = (req, res) => {
if (this.credentials) {
const auth = require("basic-auth")(req);
if (!auth || auth.name !== this.credentials.user || auth.pass !== this.credentials.pass) {
res.statusCode = 401;
res.setHeader("WWW-Authenticate", 'Basic realm="Access to stats"');
res.end("Access denied");
return;
}
}
const url = require("url").parse(req.url);
const proxyStats = this.getStats();
let body = JSON.stringify({
code: 404,
error: "Not Found"
});

if (url.pathname === "/stats") {
const body = JSON.stringify(this.getStats(), null, 2);
res.writeHead(200, {
"Content-Length": Buffer.byteLength(body),
"Content-Type": "application/json"
});
res.end(body);
body = JSON.stringify(
{
miners: proxyStats.miners.length,
connections: proxyStats.connections.length
},
null,
2
);
}

if (url.pathname === "/miners") {
body = JSON.stringify(proxyStats.miners, null, 2);
}

if (url.pathname === "/connections") {
body = JSON.stringify(proxyStats.connections, null, 2);
}

res.writeHead(200, {
"Content-Length": Buffer.byteLength(body),
"Content-Type": "application/json"
});
res.end(body);
};
if (isHTTPS) {
const certificates = {
Expand Down Expand Up @@ -207,13 +242,33 @@ class Proxy extends EventEmitter {
getStats(): Stats {
return Object.keys(this.connections).reduce(
(stats, key) => ({
miners:
stats.miners + this.connections[key].reduce((miners, connection) => miners + connection.miners.length, 0),
connections: stats.connections + this.connections[key].filter(connection => !connection.donation).length
miners: [
...stats.miners,
...this.connections[key].reduce(
(miners, connection) => [
...miners,
...connection.miners.map(miner => ({
id: miner.id,
login: miner.login,
hashes: miner.hashes
}))
],
[]
)
],
connections: [
...stats.connections,
...this.connections[key].filter(connection => !connection.donation).map(connection => ({
id: connection.id,
host: connection.host,
port: connection.port,
miners: connection.miners.length
}))
]
}),
{
miners: 0,
connections: 0
miners: [],
connections: []
}
);
}
Expand Down
17 changes: 16 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,21 @@ export type TakenJob = Job & {
};

export type Stats = {
miners: MinerStats[];
connections: ConnectionStats[];
};

export type MinerStats = {
id: string;
login: string | null;
hashes: number;
};

export type ConnectionStats = {
id: string;
host: string;
port: string;
miners: number;
connections: number;
};

export type WebSocketQuery = {
Expand All @@ -39,6 +52,8 @@ export type Socket = NodeJS.Socket & {
setKeepAlive: (value: boolean) => void;
};

export type Credentials = { user: string; pass: string };

// CoinHive

export type CoinHiveRequest = {
Expand Down

0 comments on commit 0ce74ee

Please sign in to comment.