test-ros-server.js 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. const ROS = require('realm-object-server');
  2. const fs = require('fs');
  3. const http = require('http');
  4. const httpProxy = require('http-proxy');
  5. const os = require('os');
  6. const path = require('path');
  7. // Bypass the mandatory email prompt.
  8. process.env.ROS_TOS_EMAIL_ADDRESS = 'ci@realm.io';
  9. process.env.DOCKER_DATA_PATH = '/tmp';
  10. // Don't bother calling fsync() because we're throwing away all the files
  11. // between runs anyway
  12. process.env.REALM_DISABLE_SYNC_TO_DISK = 'true';
  13. // Workaround for <https://github.com/realm/realm-object-server-private/issues/950>.
  14. process.env.ROS_SUPERAGENT_RETRY_DELAY = '0';
  15. // Enable timestamps in the logs
  16. process.env.ROS_LOG_TIMESTAMP = '1';
  17. if (!process.env.SYNC_WORKER_FEATURE_TOKEN) {
  18. try {
  19. require(os.homedir() + '/.ros-feature-token.js');
  20. }
  21. catch (e) {
  22. console.error('ROS feature token not found. Running Object Server tests requires setting the SYNC_WORKER_FEATURE_TOKEN environment variable.');
  23. process.exit(1);
  24. }
  25. }
  26. // A "email handler" which actually just writes the tokens to files that the
  27. // tests can read
  28. class PasswordEmailHandler {
  29. constructor(dataRoot) {
  30. this.dataRoot = dataRoot;
  31. fs.mkdirSync(this.dataRoot);
  32. }
  33. resetPassword(email, token, userAgent, remoteIp) {
  34. fs.writeFileSync(path.join(this.dataRoot, email), token);
  35. return new Promise(r => setTimeout(r, 0));
  36. }
  37. confirmEmail(email, token) {
  38. fs.writeFileSync(path.join(this.dataRoot, email), token);
  39. return new Promise(r => setTimeout(r, 0));
  40. }
  41. }
  42. // A simple proxy server that runs in front of ROS and validates custom headers
  43. class HeaderValidationProxy {
  44. constructor(listenPort, targetPort) {
  45. this.proxy = httpProxy.createProxyServer({target: `http://127.0.0.1:${targetPort}`, ws: true});
  46. this.proxy.on('error', e => {
  47. console.log('proxy error', e);
  48. });
  49. this.server = http.createServer((req, res) => {
  50. if (this.validate(req)) {
  51. this.proxy.web(req, res);
  52. }
  53. else {
  54. res.writeHead(400);
  55. res.end('Missing X-Allow-Connection header');
  56. }
  57. });
  58. this.server.on('upgrade', (req, socket, head) => {
  59. if (this.validate(req)) {
  60. this.proxy.ws(req, socket, head);
  61. }
  62. else {
  63. socket.end('HTTP/1.1 400 Bad Request\r\n\r\n');
  64. }
  65. });
  66. this.server.listen(listenPort);
  67. }
  68. stop() {
  69. this.server.close();
  70. this.proxy.close();
  71. }
  72. validate(req) {
  73. return !!req.headers['x-allow-connection'];
  74. }
  75. }
  76. const server = new ROS.BasicServer();
  77. server.start({
  78. // The desired logging threshold. Can be one of: all, trace, debug, detail, info, warn, error, fatal, off)
  79. logLevel: 'off',
  80. // For all the full list of configuration parameters see:
  81. // https://realm.io/docs/realm-object-server/latest/api/ros/interfaces/serverconfig.html
  82. address: '0.0.0.0',
  83. port: 9080,
  84. httpsPort: 9443,
  85. https: true,
  86. httpsKeyPath: __dirname + '/certificates/localhost-cert-key.pem',
  87. httpsCertChainPath: __dirname + '/certificates/localhost-cert.pem',
  88. httpsForInternalComponents: false,
  89. dataPath: process.argv[2],
  90. authProviders: [
  91. new ROS.auth.DebugAuthProvider(),
  92. new ROS.auth.PasswordAuthProvider({
  93. autoCreateAdminUser: true,
  94. emailHandler: new PasswordEmailHandler(path.join(process.argv[2], 'email')),
  95. }),
  96. ],
  97. autoKeyGen: true,
  98. }).then(() => {
  99. console.log('started');
  100. fs.closeSync(1);
  101. }).catch(err => {
  102. console.error(`Error starting Realm Object Server: ${err.message}`)
  103. });
  104. new HeaderValidationProxy(9081, 9080);