Source: components/app-service-bot.js

  1. "use strict";
  2. /**
  3. * Construct an AS bot user which has various helper methods.
  4. * @constructor
  5. * @param {MatrixClient} client The client instance configured for the AS bot.
  6. * @param {AppServiceRegistration} registration The registration that the bot
  7. * is following. Used to determine which user IDs it is controlling.
  8. * @param {MembershipCache} memberCache The bridges membership cache instance,
  9. * for storing membership the bot has discovered.
  10. */
  11. function AppServiceBot(client, registration, memberCache) {
  12. this.client = client;
  13. this.registration = registration.getOutput();
  14. this.memberCache = memberCache;
  15. var self = this;
  16. // yank out the exclusive user ID regex strings
  17. this.exclusiveUserRegexes = [];
  18. if (this.registration.namespaces && this.registration.namespaces.users) {
  19. this.registration.namespaces.users.forEach(function(userEntry) {
  20. if (!userEntry.exclusive) {
  21. return;
  22. }
  23. self.exclusiveUserRegexes.push(userEntry.regex);
  24. });
  25. }
  26. }
  27. AppServiceBot.prototype.getClient = function() {
  28. return this.client;
  29. };
  30. AppServiceBot.prototype.getUserId = function() {
  31. return this.client.credentials.userId;
  32. };
  33. /**
  34. * Get a list of joined room IDs for the AS bot.
  35. * @return {Promise<string[],Error>} Resolves to a list of room IDs.
  36. */
  37. AppServiceBot.prototype.getJoinedRooms = function() {
  38. return this.client.getJoinedRooms().then((res) => {
  39. if (!res.joined_rooms) {
  40. return [];
  41. }
  42. return res.joined_rooms;
  43. });
  44. };
  45. /**
  46. * Get a map of joined user IDs for the given room ID. The values in the map are objects
  47. * with a 'display_name' and 'avatar_url' properties. These properties may be null.
  48. * @param {string} roomId The room to get a list of joined user IDs in.
  49. * @return {Promise<Object,Error>} Resolves to a map of user ID => display_name avatar_url
  50. */
  51. AppServiceBot.prototype.getJoinedMembers = function(roomId) {
  52. return this.client.getJoinedRoomMembers(roomId).then((res) => {
  53. if (!res.joined) {
  54. return {};
  55. }
  56. for (const member in res.joined) {
  57. if (this.isRemoteUser(member)) {
  58. this.memberCache.setMemberEntry(roomId, member, "join");
  59. }
  60. }
  61. return res.joined;
  62. });
  63. };
  64. /**
  65. * @deprecated
  66. * @throws {Error} This will always throw because /sync is no longer supported.
  67. */
  68. AppServiceBot.prototype.getMemberLists = function() {
  69. throw new Error(
  70. "The appservice bot can no longer /sync because this functionality was removed." +
  71. "Please use getJoinedRooms and getJoinedMembers"
  72. );
  73. };
  74. AppServiceBot.prototype._getRoomInfo = function(roomId, joinedRoom) {
  75. var self = this;
  76. var stateEvents = joinedRoom.state ? joinedRoom.state.events : [];
  77. var roomInfo = {
  78. id: roomId,
  79. state: stateEvents,
  80. realJoinedUsers: [],
  81. remoteJoinedUsers: []
  82. };
  83. stateEvents.forEach(function(event) {
  84. if (event.type !== "m.room.member" || event.content.membership !== "join") {
  85. return;
  86. }
  87. var userId = event.state_key;
  88. if (userId === self.getUserId()) {
  89. return;
  90. }
  91. if (self.isRemoteUser(userId)) {
  92. roomInfo.remoteJoinedUsers.push(userId);
  93. }
  94. else {
  95. roomInfo.realJoinedUsers.push(userId);
  96. }
  97. });
  98. return roomInfo;
  99. }
  100. /**
  101. * Test a userId to determine if it's a user within the exclusive regexes of the bridge.
  102. * @return {boolean} True if it is a remote user, false otherwise.
  103. */
  104. AppServiceBot.prototype.isRemoteUser = function(userId) {
  105. for (var i = 0; i < this.exclusiveUserRegexes.length; i++) {
  106. var regex = new RegExp(this.exclusiveUserRegexes[i]);
  107. if (regex.test(userId)) {
  108. return true;
  109. }
  110. }
  111. return false;
  112. };
  113. // Backwards compatible for many bridges that make use of _isRemoteUser
  114. AppServiceBot.prototype._isRemoteUser = AppServiceBot.prototype.isRemoteUser;
  115. module.exports = AppServiceBot;
  116. /**
  117. * @typedef AppServiceBot~RoomInfo
  118. * @type {Object}
  119. * @property {string} id The matrix room ID
  120. * @property {Object[]} state The raw state events for this room
  121. * @property {string[]} realJoinedUsers A list of user IDs of real matrix users
  122. * that have joined this room.
  123. * @property {string[]} remoteJoinedUsers A list of user IDs of remote users
  124. * (provisioned by the AS) that have joined this room.
  125. */