UNPKG

openhim-core

Version:

The OpenHIM core application that provides logging and routing of http requests

417 lines (353 loc) 15.1 kB
http = require "http" https = require "https" net = require "net" tls = require "tls" fs = require "fs" Transaction = require('../lib/model/transactions').Transaction User = require('../lib/model/users').User Keystore = require('../lib/model/keystore').Keystore crypto = require "crypto" zlib = require "zlib" pem = require "pem" logger = require "winston" Q = require "q" finalhandler = require('finalhandler') serveStatic = require('serve-static') exports.createMockServer = (resStatusCode, resBody, port, callback, requestCallback) -> requestCallback = requestCallback || -> # Create mock endpoint to forward requests to mockServer = http.createServer (req, res) -> res.writeHead resStatusCode, {"Content-Type": "text/plain"} res.end resBody mockServer.listen port, -> callback mockServer mockServer.on "request", requestCallback return mockServer exports.createMockServerForPost = (successStatusCode, errStatusCode, bodyToMatch) -> return http.createServer (req, res) -> req.on "data", (chunk) -> if chunk.toString() == bodyToMatch res.writeHead successStatusCode, {"Content-Type": "text/plain"} res.end() else res.writeHead errStatusCode, {"Content-Type": "text/plain"} res.end() exports.createStaticServer = (path, port, callback) -> # Serve up public/ftp folder serve = serveStatic(path, 'index': [ 'index.html' 'index.htm' ]) # Create server server = http.createServer((req, res) -> done = finalhandler(req, res) serve req, res, done return ) # Listen server.listen port, 'localhost', -> callback server exports.createMockHTTPSServerWithMutualAuth = (resStatusCode, resBody, port, useClientCert, callback, requestCallback) -> if typeof useClientCert is 'function' requestCallback = callback callback = useClientCert useClientCert = true options = key: fs.readFileSync 'test/resources/server-tls/key.pem' cert: fs.readFileSync 'test/resources/server-tls/cert.pem' requestCert: true rejectUnauthorized: true secureProtocol: 'TLSv1_method' if useClientCert options.ca = fs.readFileSync 'test/resources/server-tls/cert.pem' requestCallback = requestCallback || -> # Create mock endpoint to forward requests to mockServer = https.createServer options, (req, res) -> res.writeHead resStatusCode, {"Content-Type": "text/plain"} res.end "Secured " + resBody mockServer.listen port, -> callback mockServer mockServer.on "request", requestCallback exports.createMockTCPServer = (port, expected, matchResponse, nonMatchResponse, callback, onRequest=(->)) -> server = net.createServer (sock) -> sock.on 'data', (data) -> onRequest data response = if "#{data}" is expected then matchResponse else nonMatchResponse sock.write response server.listen port, 'localhost', -> callback server exports.createMockTLSServerWithMutualAuth = (port, expected, matchResponse, nonMatchResponse, useClientCert, callback, onRequest=(->)) -> if typeof useClientCert is 'function' onRequest = callback || -> callback = useClientCert useClientCert = true options = key: fs.readFileSync 'test/resources/server-tls/key.pem' cert: fs.readFileSync 'test/resources/server-tls/cert.pem' requestCert: true rejectUnauthorized: true secureProtocol: 'TLSv1_method' if useClientCert options.ca = fs.readFileSync 'test/resources/server-tls/cert.pem' server = tls.createServer options, (sock) -> sock.on 'data', (data) -> onRequest data response = if "#{data}" is expected then matchResponse else nonMatchResponse sock.write response server.listen port, 'localhost', -> callback server exports.createMockHTTPRespondingPostServer = (port, expected, matchResponse, nonMatchResponse, callback) -> server = http.createServer (req, res) -> req.on 'data', (data) -> if "#{data}" is expected res.writeHead 200, {"Content-Type": "text/plain"} res.write matchResponse else res.writeHead 500, {"Content-Type": "text/plain"} res.write nonMatchResponse res.end() server.listen port, 'localhost', -> callback server exports.createMockMediatorServer = (resStatusCode, mediatorResponse, port, callback) -> requestCallback = requestCallback || -> # Create mock endpoint to forward requests to mockServer = http.createServer (req, res) -> res.writeHead resStatusCode, {"Content-Type": "application/json+openhim; charset=utf-8"} res.end JSON.stringify mediatorResponse mockServer.listen port, -> callback mockServer exports.createSlowMockMediatorServer = (delay, resStatusCode, resBody, port, callback, requestCallback) -> requestCallback = requestCallback || -> # Create mock endpoint to forward requests to mockServer = http.createServer (req, res) -> respond = -> res.writeHead resStatusCode, {"Content-Type": "application/json+openhim; charset=utf-8"} res.end JSON.stringify resBody setTimeout respond, delay mockServer.listen port, -> callback mockServer mockServer.on "request", requestCallback return mockServer exports.rootUser = firstname: 'Admin' surname: 'User' email: 'root@jembi.org' passwordAlgorithm: 'sha512' passwordHash: '669c981d4edccb5ed61f4d77f9fcc4bf594443e2740feb1a23f133bdaf80aae41804d10aa2ce254cfb6aca7c497d1a717f2dd9a794134217219d8755a84b6b4e' passwordSalt: '22a61686-66f6-483c-a524-185aac251fb0' groups: [ 'HISP', 'admin' ] # password is 'password' exports.nonRootUser = firstname: 'Non' surname: 'Root' email: 'nonroot@jembi.org' passwordAlgorithm: 'sha512' passwordHash: '669c981d4edccb5ed61f4d77f9fcc4bf594443e2740feb1a23f133bdaf80aae41804d10aa2ce254cfb6aca7c497d1a717f2dd9a794134217219d8755a84b6b4e' passwordSalt: '22a61686-66f6-483c-a524-185aac251fb0' groups: [ "group1", "group2" ] # password is 'password' exports.auth = {} exports.auth.setupTestUsers = (done) -> (new User exports.rootUser).save (err) -> return done err if err (new User exports.nonRootUser).save (err) -> if err done err else done() # auth detail are the same between the to users exports.auth.getAuthDetails = () -> # create tokenhash authTS = new Date().toISOString() requestsalt = '842cd4a0-1a91-45a7-bf76-c292cb36b2e8' tokenhash = crypto.createHash 'sha512' tokenhash.update exports.rootUser.passwordHash tokenhash.update requestsalt tokenhash.update authTS auth = authTS: authTS authSalt: requestsalt authToken: tokenhash.digest('hex') return auth exports.auth.cleanupTestUsers = (done) -> User.remove { email: 'root@jembi.org' }, (err) -> return done err if err User.remove { email: 'nonroot@jembi.org' }, (err) -> if err done err else done() exports.createMockServerForPostWithReturn = (successStatusCode, errStatusCode, bodyToMatch) -> return http.createServer (req, res) -> acceptEncoding = req.headers['accept-encoding'] if (!acceptEncoding) acceptEncoding = '' req.on "data", (chunk) -> if chunk.toString() == bodyToMatch if acceptEncoding.match /gzip/g #the him always sets the accept-encoding headers to accept gzip it then decompresses the response and sends it to the client buf = new Buffer(bodyToMatch, 'utf-8') zlib.gzip bodyToMatch, (_, result) -> headers = "date": (new Date()).toString() "vary": "Accept-Encoding" "server": "Apache" "allow": "GET,HEAD,POST,PUT,OPTIONS" "content-type": "text/html" "content-encoding": "gzip" "content-length": result.length "connection": "close" res.writeHead successStatusCode, headers res.end result else res.writeHead successStatusCode, {"Content-Type": "text/plain"} res.end bodyToMatch else res.writeHead errStatusCode, {"Content-Type": "text/plain"} res.end() ### # Sets up a keystore of testing. serverCert, serverKey, ca are optional, however if # you provide a serverCert you must provide the serverKey or null one out and vice # versa. ### exports.setupTestKeystore = (serverCert, serverKey, ca, callback) -> if typeof serverCert is 'function' callback = serverCert serverCert = null if serverCert instanceof Array and typeof serverKey is 'function' ca = serverCert callback = serverKey serverCert = null serverKey = null serverCert = fs.readFileSync 'test/resources/server-tls/cert.pem' if not serverCert? serverKey = fs.readFileSync 'test/resources/server-tls/key.pem' if not serverKey? if not ca? ca = [] ca.push fs.readFileSync 'test/resources/trust-tls/cert1.pem' ca.push fs.readFileSync 'test/resources/trust-tls/cert2.pem' # remove any existing keystore Keystore.remove {}, -> pem.readCertificateInfo serverCert, (err, serverCertInfo) -> if err? logger.error "Failed to get certificate info in test utils: #{err}" return callback null serverCertInfo.data = serverCert pem.getFingerprint serverCert, (err, serverCertFingerprint) -> if err? logger.error "Failed to get certificate fingerprint in test utils: #{err}" return callback null serverCertInfo.fingerprint = serverCertFingerprint.fingerprint keystore = new Keystore key: serverKey cert: serverCertInfo ca: [] if ca.length > 0 readCertInfo = Q.denodeify pem.readCertificateInfo getFingerprint = Q.denodeify pem.getFingerprint infoPromises = [] fingerprintPromises = [] for cert in ca infoPromises.push(readCertInfo cert) fingerprintPromises.push(getFingerprint cert) Q.all(infoPromises).then (caCertsInfo) -> Q.all(fingerprintPromises).then (caFingerprints) -> keystore.ca = caCertsInfo # Add in the cert data for cert, i in ca keystore.ca[i].data = cert keystore.ca[i].fingerprint = caFingerprints[i].fingerprint keystore.save -> callback keystore else keystore.save -> callback keystore exports.cleanupTestKeystore = (callback) -> Keystore.remove {}, -> callback() exports.setupMetricsTransactions = (callback) -> transaction0 = new Transaction # 1 month before the rest _id: "000000000000000000000000" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-06-15T08:10:45.100Z" } response: { status: "200", timestamp: "2014-06-15T08:10:45.200Z" } status: "Completed" transaction1 = new Transaction _id: "111111111111111111111111" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-15T08:10:45.100Z" } response: { status: "200", timestamp: "2014-07-15T08:10:45.200Z" } status: "Completed" transaction2 = new Transaction _id: "222222222222222222222222" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-15T14:30:45.100Z" } response: { status: "200", timestamp: "2014-07-15T14:30:45.300Z" } status: "Successful" transaction3 = new Transaction _id: "333333333333333333333333" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-15T19:46:45.100Z" } response: { status: "200", timestamp: "2014-07-15T19:46:45.200Z" } status: "Completed" transaction4 = new Transaction _id: "444444444444444444444444" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-16T09:15:45.100Z" } response: { status: "404", timestamp: "2014-07-16T09:15:45.300Z" } status: "Failed" transaction5 = new Transaction _id: "555555555555555555555555" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-16T13:30:45.100Z" } response: { status: "200", timestamp: "2014-07-16T13:30:45.200Z" } status: "Completed" transaction6 = new Transaction _id: "666666666666666666666666" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-16T16:10:39.100Z" } response: { status: "200", timestamp: "2014-07-16T16:10:39.300Z" } status: "Completed" transaction7 = new Transaction _id: "777777777777777777777777" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-17T14:45:20.100Z" } response: { status: "200", timestamp: "2014-07-17T14:45:20.200Z" } status: "Completed with error(s)" transaction8 = new Transaction _id: "888888888888888888888888" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-17T19:21:45.100Z" } response: { status: "200", timestamp: "2014-07-17T19:21:45.300Z" } status: "Completed" transaction9 = new Transaction _id: "999999999999999999999999" channelID: "111111111111111111111111" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-18T11:17:45.100Z" } response: { status: "404", timestamp: "2014-07-18T11:17:45.200Z" } status: "Processing" transaction10 = new Transaction _id: "101010101010101010101010" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2014-07-18T11:25:45.100Z" } response: { status: "200", timestamp: "2014-07-18T11:25:45.300Z" } status: "Completed" transaction11 = new Transaction # 1 year after the rest _id: "111110101010101010101111" channelID: "222222222222222222222222" clientID: "42bbe25485e77d8e5daad4b4" request: { path: "/sample/api", method: "GET", timestamp: "2015-07-18T13:25:45.100Z" } response: { status: "200", timestamp: "2015-07-18T13:25:45.300Z" } status: "Completed" transaction0.save (err) -> transaction1.save (err) -> transaction2.save (err) -> transaction3.save (err) -> transaction4.save (err) -> transaction5.save (err) -> transaction6.save (err) -> transaction7.save (err) -> transaction8.save (err) -> transaction9.save (err) -> transaction10.save (err) -> transaction11.save (err) -> callback()