java-topology/defects/wekan-0003/patch/wekan-0003.patch
russell@unturf.com 60b0999acd wekan+rocketchat: 3 defects, all 5 MOADs scanned
wekan-0003: MOAD-0001 wekanCreator.js member dedup uses Array.some()/find()
  inside forEach inside for-of, O(M^2) for board members and O(C*M^2) for
  card members/assignees during board import. Fix: Set-based dedup O(1).
  58.8x op-count reduction (board), 5.6x (cards). 4/4 PASS.

rocketchat-0003: MOAD-0001 endDirectCall() calls call.users.find() inside
  for (subscription of subscriptions), O(S*U) where S=room members and
  U=already-joined users. Fix: build Set before loop for O(1) lookup.
  100x speedup modeled at S=10000, J=100. 5/5 PASS.

rocketchat-0004: MOAD-0004 CWE-312 oauth2-server/model.ts logs clientSecret,
  accessToken, refreshToken, and authorizationCode verbatim via console.log
  when debug=true. Fix: replace credential values with [REDACTED] sentinel.

Wekan MOAD-0002/0003/0004/0005 CLEAN (Meteor 3.4, AsyncLocalStorage, no
god-object coupling, no credential logging found, no concurrent cache race).
Rocket.Chat MOAD-0002/0003/0005 CLEAN (Meteor 3.3.2, AsyncLocalStorage,
clientVersionsStore single-writer, service boundaries intact).
2026-03-31 20:50:31 -04:00

98 lines
3.7 KiB
Diff

--- a/models/wekanCreator.js
+++ b/models/wekanCreator.js
@@ -323,11 +323,13 @@ class WekanCreator {
// now add other members
if (boardToImport.members) {
- boardToImport.members.forEach(wekanMember => {
- // is it defined and do we already have it in our list?
- if (
- wekanMember.wekanId &&
- !boardToCreate.members.some(
- member => member.wekanId === wekanMember.wekanId,
- )
- )
- boardToCreate.members.push({
- ...wekanMember,
- userId: wekanMember.wekanId,
- });
- });
+ // Build a Set of already-present wekanIds so dedup is O(1) per member
+ // instead of O(M) per member (was O(M^2) overall).
+ const seenWekanIds = new Set(
+ boardToCreate.members.map(m => m.wekanId).filter(Boolean),
+ );
+ boardToImport.members.forEach(wekanMember => {
+ if (wekanMember.wekanId && !seenWekanIds.has(wekanMember.wekanId)) {
+ seenWekanIds.add(wekanMember.wekanId);
+ boardToCreate.members.push({
+ ...wekanMember,
+ userId: wekanMember.wekanId,
+ });
+ }
+ });
}
@@ -410,18 +412,22 @@ class WekanCreator {
// add members
if (card.members) {
- const wekanMembers = [];
- // we can't just map, as some members may not have been mapped
- card.members.forEach(sourceMemberId => {
- if (this.members[sourceMemberId]) {
- const wekanId = this.members[sourceMemberId];
- // we may map multiple Wekan members to the same wekan user
- // in which case we risk adding the same user multiple times
- if (!wekanMembers.find(wId => wId === wekanId)) {
- wekanMembers.push(wekanId);
- }
- }
- return true;
- });
+ // Use a Set for O(1) dedup instead of Array.find() O(M) per member.
+ const seenMemberIds = new Set();
+ const wekanMembers = [];
+ card.members.forEach(sourceMemberId => {
+ if (this.members[sourceMemberId]) {
+ const wekanId = this.members[sourceMemberId];
+ if (!seenMemberIds.has(wekanId)) {
+ seenMemberIds.add(wekanId);
+ wekanMembers.push(wekanId);
+ }
+ }
+ return true;
+ });
if (wekanMembers.length > 0) {
cardToCreate.members = wekanMembers;
}
@@ -429,18 +435,22 @@ class WekanCreator {
// add assignees
if (card.assignees) {
- const wekanAssignees = [];
- // we can't just map, as some members may not have been mapped
- card.assignees.forEach(sourceMemberId => {
- if (this.members[sourceMemberId]) {
- const wekanId = this.members[sourceMemberId];
- // we may map multiple Wekan members to the same wekan user
- // in which case we risk adding the same user multiple times
- if (!wekanAssignees.find(wId => wId === wekanId)) {
- wekanAssignees.push(wekanId);
- }
- }
- return true;
- });
+ // Same Set-based dedup for assignees.
+ const seenAssigneeIds = new Set();
+ const wekanAssignees = [];
+ card.assignees.forEach(sourceMemberId => {
+ if (this.members[sourceMemberId]) {
+ const wekanId = this.members[sourceMemberId];
+ if (!seenAssigneeIds.has(wekanId)) {
+ seenAssigneeIds.add(wekanId);
+ wekanAssignees.push(wekanId);
+ }
+ }
+ return true;
+ });
if (wekanAssignees.length > 0) {
cardToCreate.assignees = wekanAssignees;
}