IdentificationService.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. /*
  2. * Copyright (C) 2024 Puter Technologies Inc.
  3. *
  4. * This file is part of Puter.
  5. *
  6. * Puter is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Affero General Public License as published
  8. * by the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Affero General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Affero General Public License
  17. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. */
  19. const { AdvancedBase } = require("@heyputer/puter-js-common");
  20. const BaseService = require("../BaseService");
  21. const { Context } = require("../../util/context");
  22. const config = require("../../config");
  23. class Requester {
  24. constructor (o) {
  25. for ( const k in o ) this[k] = o[k];
  26. }
  27. static create (o) {
  28. return new Requester(o);
  29. }
  30. static from_request (req) {
  31. const has_referer = req.headers['referer'] !== undefined;
  32. let referer_url;
  33. let referer_origin;
  34. if ( has_referer ) {
  35. try {
  36. referer_url = new URL(req.headers['referer']);
  37. referer_origin = referer_url.origin;
  38. } catch (e) {
  39. // URL is invalid; referer_url and referer_origin will be undefined
  40. }
  41. }
  42. return new Requester({
  43. ua: req.headers['user-agent'],
  44. ip: req.connection.remoteAddress,
  45. ip_forwarded: req.headers['x-forwarded-for'],
  46. origin: req.headers['origin'],
  47. referer: req.headers['referer'],
  48. referer_origin,
  49. });
  50. }
  51. is_puter_referer () {
  52. const puter_origins = [
  53. config.origin,
  54. config.api_base_url,
  55. ]
  56. return puter_origins.includes(this.referer_origin);
  57. }
  58. is_puter_origin () {
  59. const puter_origins = [
  60. config.origin,
  61. config.api_base_url,
  62. ]
  63. return puter_origins.includes(this.origin);
  64. }
  65. get rl_identifier () {
  66. return this.ip_forwarded || this.ip;
  67. }
  68. serialize () {
  69. return {
  70. ua: this.ua,
  71. ip: this.ip,
  72. ip_forwarded: this.ip_forwarded,
  73. referer: this.referer,
  74. referer_origin: this.referer_origin,
  75. };
  76. }
  77. }
  78. // DRY: (3/3) - src/util/context.js; move install() to base class
  79. class RequesterIdentificationExpressMiddleware extends AdvancedBase {
  80. static MODULES = {
  81. isbot: require('isbot'),
  82. }
  83. register_initializer (initializer) {
  84. this.value_initializers_.push(initializer);
  85. }
  86. install (app) {
  87. app.use(this.run.bind(this));
  88. }
  89. async run (req, res, next) {
  90. const x = Context.get();
  91. const requester = Requester.from_request(req);
  92. const is_bot = this.modules.isbot(requester.ua);
  93. requester.is_bot = is_bot;
  94. x.set('requester', requester);
  95. req.requester = requester;
  96. if ( requester.is_bot ) {
  97. this.log.info('bot detected', requester.serialize());
  98. }
  99. next();
  100. }
  101. }
  102. class IdentificationService extends BaseService {
  103. _construct () {
  104. this.mw = new RequesterIdentificationExpressMiddleware();
  105. }
  106. _init () {
  107. this.mw.log = this.log;
  108. }
  109. async ['__on_install.middlewares.context-aware'] (_, { app }) {
  110. this.mw.install(app);
  111. }
  112. }
  113. module.exports = {
  114. IdentificationService,
  115. };