Skip to content

Commit

Permalink
Add SSL/TLS support
Browse files Browse the repository at this point in the history
  • Loading branch information
rlidwka committed Mar 23, 2017
1 parent 15097d5 commit 586534e
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 16 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ Address has "standard" format to define everything in one string:
`nttp(s)://hostname:port/?option1=value1&option2=value2`. For example:

- `nntp://example.com` - listen on 119 port
- `nntps://example.com` - listen 569 port, encrypted
- `nntps://example.com` - listen on 563 port, encrypted

options:

Expand Down
35 changes: 20 additions & 15 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
const glob = require('glob');
const net = require('net');
const path = require('path');
const tls = require('tls');
const url = require('url');
const Promise = require('bluebird');
const Session = require('./lib/session');
Expand All @@ -35,6 +36,8 @@ const DEFAULT_OPTIONS = {
// proxy or use built-in NTTPS. Default server on 119 port is not secure,
// and AUTHINFO will require to upgrade connection via STARTSSL.
secure: false,
// TLS/SSL options (see node.js TLS documentation).
tls: null,
session: Session,
commands
};
Expand All @@ -43,29 +46,31 @@ const DEFAULT_OPTIONS = {
function Nntp(options) {
this.options = Object.assign({}, DEFAULT_OPTIONS, options || {});

this.ssl = false;
this.commands = this.options.commands;
}


Nntp.prototype.listen = function (address) {
let host, port;
let parsed = url.parse(address);

this.server = net.createServer(connection => {
let listener = connection => {
this.options.session.create(this, connection);
});
}
};

host = parsed.hostname || 'localhost';

if (parsed.protocol === 'nntps:') {
this.server = tls.createServer(this.options.tls, listener);

Nntp.prototype.listen = function (...args) {
if (typeof args[0] === 'string') {
// support and parse 'nntp:' protocol for:
// listen(path[, backlog][, callback])
let parsed = url.parse(args[0]);
port = parsed.port !== null ? parsed.port : 563;
} else {
this.server = net.createServer(listener);

if (parsed && parsed.protocol === 'nntp:') {
args.shift();
args.unshift(parsed.hostname || 'localhost');
args.unshift(parsed.port || 119);
}
port = parsed.port !== null ? parsed.port : 119;
}

return Promise.fromCallback(cb => { this.server.listen(...args, cb); });
return Promise.fromCallback(cb => { this.server.listen(port, host, cb); });
};


Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/server-cert.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
-----BEGIN CERTIFICATE-----
MIIDDjCCAfYCCQDWm33tO7TIBTANBgkqhkiG9w0BAQsFADBIMQswCQYDVQQGEwJq
czEPMA0GA1UECAwGbm9kZWNhMRQwEgYDVQQKDAtubnRwLXNlcnZlcjESMBAGA1UE
AwwJbG9jYWxob3N0MCAXDTE3MDMyMzE1MzkwM1oYDzIxMDMwMTA5MTUzOTAzWjBI
MQswCQYDVQQGEwJqczEPMA0GA1UECAwGbm9kZWNhMRQwEgYDVQQKDAtubnRwLXNl
cnZlcjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
MIIBCgKCAQEAlg0dnUDw4tmKeBB5A/lQFoNgxiw+8Jo0BUAU3k47SrEkWGEH8xhx
spGeM7HDoBicbMQV6vcNSOT1Q5kSC5NhaImxG5FhkuwhR9wwmbb1b/+dRltjdCh4
wngwOnz5hDm3mPkvEoW7XEE7s40Pgz9PnK94I4hhuYBb3cWMauUyjjRGkn967EbJ
Wd4p8z3gy42POXpNZpk/7Po7sRr+UJn9Uesj9GXx7oU8QTWQYlmWFOISjaK7wJ98
Ytk/Gu+zwohgSjrU9rultW/xUaRzCrXe5P5npFR1m+XQYC4O78r5Zz7pYuPdgfrJ
RIxRV7Kw/ZBxGyvYe6WfmUo4osPVtsLIlQIDAQABMA0GCSqGSIb3DQEBCwUAA4IB
AQAFDpIKvIShO5iX3j++/JYFES8jdK+I8oaU7UZ7/6ijF2UD0gQFe+DqmXcWu1Gg
lSKa/tvZzesJrDpTuwYjyh3OSUpAIvbJxLE8Qi8lMmujHNnWm+kfVCrr/4SI3Vio
EjEkilsgToAU80G6YY7p/6uNv0N4upGWp8ZXNploi8LYLt+EH30AQJgUs5u4d6qT
IhVdWEDvXrBjTtpS2PfkEyNT121RyjzqCw9suf/cnNpIcirO+KnfpWocCW5GFdm1
xQP3ygmkVkplkEgIhQSGzBye+soitIs91KlLSNZguK5NsLhDR50iUQ5CpcDQpl57
GsOJu+XHWwKWc+XwnXfiyesT
-----END CERTIFICATE-----
27 changes: 27 additions & 0 deletions test/fixtures/server-key.pem
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAlg0dnUDw4tmKeBB5A/lQFoNgxiw+8Jo0BUAU3k47SrEkWGEH
8xhxspGeM7HDoBicbMQV6vcNSOT1Q5kSC5NhaImxG5FhkuwhR9wwmbb1b/+dRltj
dCh4wngwOnz5hDm3mPkvEoW7XEE7s40Pgz9PnK94I4hhuYBb3cWMauUyjjRGkn96
7EbJWd4p8z3gy42POXpNZpk/7Po7sRr+UJn9Uesj9GXx7oU8QTWQYlmWFOISjaK7
wJ98Ytk/Gu+zwohgSjrU9rultW/xUaRzCrXe5P5npFR1m+XQYC4O78r5Zz7pYuPd
gfrJRIxRV7Kw/ZBxGyvYe6WfmUo4osPVtsLIlQIDAQABAoIBADUyszQkaQLUQ45r
sKvjASzqKS45U5sz4IuX+44RSF4jzZHz3MCoAu9fRypmtMeW0iaRon+qVTBp1DbC
Fy65csiAQKVYdrKDOw1iGGz2+69YfacLEYiGLMItoFOsKT5ixB/dAH5doV6E1ijD
MyPCF3SilUJrwNHmmytWNYFUfwcBIKbPWUy6q/z6KFGI+YUIvDh8rAD7M785bAWq
k8Im4vh1Bj+OVUyYztxqA3JVFAP8dEi9SnLdQMyDc7GyXSkynCj3vdOH+WnP1c0h
dI9nojHjEOXRVQeWjOlQ53ybQk4HUUp3EmWD1DErjd5QWF1hrkRN6mkjcVqXt2W5
i4SQVuUCgYEAxF0929bjn743EfnO78LIpGliVyzbNR31HjW6/T0QDj8LBi9hiyeq
+7nuh9BSDD5qKefaowbWXuNYkl4CMenbmZUXwmrMfJXTZMfUfYPEe/hkXYvX6MEd
boEOxezpcEWVTHG7G/nBi1XvOCZRBFCIUbo8KfDJ/lEtDau7p1BuvnMCgYEAw58r
yGZQWN4T6e8g4R/WehYwvyEJvOhexprpnNPqISVoVVZY7p3jD7HfuHSsDaTLcXca
h7fLbsSz+47iK+D8Ikga9y+vEgKnYkCNP9VHHBtQh9gB6X5hbQi9G3JfoAMuJ4bu
mB7beN3buTe/XOjbs9KM6OoZEjmzqTEV8JxAUtcCgYEAvifxZHgHvEUu/Uhlvkdp
l9W59uOocBrPqW6s4tmEN9eTLG0rz98dNGJM/Nae7d5vXp95WdCgPgl5V1yUUZO/
Jk58ULitx6Qrr3fYbafx2X+kafanom2Iu99c2AzhzuiDeSDV6nSFmhIg88YfRMdc
C5EG/DKC2bXwpEF/GrrIU8MCgYBux1+q783GVZTfYCy1cCssHg7i3Zm/IbQyMh3j
Utp+hMmNsgVQs5aXF7rCoUehvlX7XmBmxP1uL/Rgm6yW/qSp4T1sB9PTli8l47pZ
kLThRNKY6wlCKfCQJ2e3+FAQtFxZw/6vpKHS04iPXfN/cNqh/bUQXSlveb+1K3fq
NwHyJwKBgD6vVzPQ1VQ1Zb4LWDgvjTqv0GsD3S45DfSvApAWax3E4RqAf0ymigcE
44FubXyp60OU7/JI9MG1CCqSJGg4uq5m4Apa1mYFHJjLknfBdzRrm3BjMJmZEKSH
h3/fE0PEEViAMbdDYY2OXxT9B8q4qSUfs1wt5Fj/U+p+MHS+FBOA
-----END RSA PRIVATE KEY-----
79 changes: 79 additions & 0 deletions test/security.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

'use strict';

const fs = require('fs');
const net = require('net');
const join = require('path').join;
const tls = require('tls');
const asline = require('./helpers').asline;
const Server = require('..');


describe('security', function () {
let port_plain, client_plain, socket_plain;
let port_tls, client_tls, socket_tls;

before(function () {
let nntp = new Server({ secure: false });

// listen on random port
return nntp.listen('nntp://localhost:0').then(() => {
port_plain = nntp.server.address().port;
});
});


beforeEach(function (callback) {
socket_plain = net.connect(port_plain, err => {
client_plain = asline(socket_plain, { timeout: 2000 });
callback(err);
});
});


afterEach(function () {
socket_plain.end();
});


before(function () {
let nntp = new Server({
secure: true,
tls: {
key: fs.readFileSync(join(__dirname, 'fixtures', 'server-key.pem')),
cert: fs.readFileSync(join(__dirname, 'fixtures', 'server-cert.pem'))
}
});

// listen on random port
return nntp.listen('nntps://localhost:0').then(() => {
port_tls = nntp.server.address().port;
});
});


beforeEach(function (callback) {
socket_tls = tls.connect(port_tls, {
ca: [ fs.readFileSync(join(__dirname, 'fixtures', 'server-cert.pem')) ]
}, err => {
client_tls = asline(socket_tls, { timeout: 2000 });
callback(err);
});
});


afterEach(function () {
socket_tls.end();
});


it('should allow auth over secure channel only', function () {
return Promise.resolve()
.then(() => client_plain
.send('AUTHINFO USER test')
.expect(/^483 /))
.then(() => client_tls
.send('AUTHINFO USER test')
.expect(/^381 /));
});
});

0 comments on commit 586534e

Please sign in to comment.