Skip to content

Commit ebc234a

Browse files
committed
fix: more flexible user matching
1 parent ae424c1 commit ebc234a

File tree

7 files changed

+468
-97
lines changed

7 files changed

+468
-97
lines changed

dist/index.js

Lines changed: 118 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -81717,23 +81717,72 @@ var SlackAppUrl;
8171781717
;// CONCATENATED MODULE: ./src/utils/slack/user-matchers.ts
8171881718

8171981719

81720+
/**
81721+
* Redacts sensitive information for safe logging
81722+
* Replaces characters with random alphanumeric chars of matching case
81723+
* Preserves first and last character, special chars, and word structure
81724+
*/
81725+
function redact(text) {
81726+
if (!text) {
81727+
return '';
81728+
}
81729+
// Return very short strings as is
81730+
if (text.length <= 2) {
81731+
return text;
81732+
}
81733+
// Handle email addresses by splitting at @
81734+
if (text.includes('@')) {
81735+
const [localPart, domainPart] = text.split('@');
81736+
const redactedLocal = redact(localPart);
81737+
// Redact each part of the domain separately
81738+
const domainParts = domainPart.split('.');
81739+
const redactedDomain = domainParts
81740+
.map((part, index) => {
81741+
// Preserve common TLDs and very short parts
81742+
if (part.length <= 2 ||
81743+
(index === domainParts.length - 1 &&
81744+
['ai', 'app', 'co', 'com', 'dev', 'io', 'net', 'org'].includes(part.toLowerCase()))) {
81745+
return part;
81746+
}
81747+
return redactPart(part);
81748+
})
81749+
.join('.');
81750+
return `${redactedLocal}@${redactedDomain}`;
81751+
}
81752+
return redactPart(text);
81753+
}
8172081754
function customMappingMatcher(githubUsername, slackUsername) {
8172181755
return {
81722-
check: (user) => user.name?.toLowerCase() === slackUsername.toLowerCase() ||
81723-
user.profile?.display_name?.toLowerCase() === slackUsername.toLowerCase() ||
81724-
user.profile?.real_name?.toLowerCase() === slackUsername.toLowerCase(),
81756+
check: (user) => {
81757+
const name = user.name?.toLowerCase() ?? '';
81758+
const displayName = user.profile?.display_name?.toLowerCase() ?? '';
81759+
const realName = user.profile?.real_name?.toLowerCase() ?? '';
81760+
const slackNameLower = slackUsername.toLowerCase();
81761+
return (name.includes(slackNameLower) ||
81762+
slackNameLower.includes(name) ||
81763+
displayName.includes(slackNameLower) ||
81764+
slackNameLower.includes(displayName) ||
81765+
realName.includes(slackNameLower) ||
81766+
slackNameLower.includes(realName));
81767+
},
8172581768
description: 'custom user mapping',
8172681769
log: (user) => {
8172781770
(0,core.debug)(`Match found by custom mapping: GitHub username [${githubUsername}] to Slack username [${slackUsername}] for user [${user.id}]`);
81771+
(0,core.debug)(`Redacted debug info: GitHub username [${redact(githubUsername)}] to Slack username [${redact(slackUsername)}] matched with user name [${redact(user.name ?? '')}], display_name [${redact(user.profile?.display_name ?? '')}], real_name [${redact(user.profile?.real_name ?? '')}]`);
8172881772
},
8172981773
};
8173081774
}
8173181775
function displayNameMatcher(username) {
8173281776
return {
81733-
check: (user) => user.profile?.display_name?.toLowerCase() === username.toLowerCase(),
81777+
check: (user) => {
81778+
const displayName = user.profile?.display_name?.toLowerCase() ?? '';
81779+
const usernameLower = username.toLowerCase();
81780+
return displayName.includes(usernameLower) || usernameLower.includes(displayName);
81781+
},
8173481782
description: 'user.profile.display_name fields',
8173581783
log: (user) => {
8173681784
(0,core.debug)(`Match found by username [${username}] matching Slack displayName [${user.profile?.display_name}]`);
81785+
(0,core.debug)(`Redacted debug info: username [${redact(username)}] matched with display_name [${redact(user.profile?.display_name ?? '')}]`);
8173781786
},
8173881787
};
8173981788
}
@@ -81745,6 +81794,7 @@ function emailContainsMatcher(username) {
8174581794
description: 'user.profile.email contains check',
8174681795
log: (user) => {
8174781796
(0,core.debug)(`Match found by username [${username}] contained in Slack email [${user.profile?.email}]`);
81797+
(0,core.debug)(`Redacted debug info: username [${redact(username)}] matched with email [${redact(user.profile?.email ?? '')}]`);
8174881798
},
8174981799
};
8175081800
}
@@ -81754,24 +81804,72 @@ function emailMatcher(email) {
8175481804
description: 'user.profile.email fields',
8175581805
log: (user) => {
8175681806
(0,core.debug)(`Match found by email [${email}] with Slack email [${user.profile?.email}]`);
81807+
(0,core.debug)(`Redacted debug info: email [${redact(email)}] matched with Slack email [${redact(user.profile?.email ?? '')}]`);
8175781808
},
8175881809
};
8175981810
}
81811+
/**
81812+
* Get a random character from a character set
81813+
*/
81814+
function getRandomChar(charSet) {
81815+
const randomIndex = Math.floor(Math.random() * charSet.length);
81816+
return charSet[randomIndex];
81817+
}
8176081818
function realNameMatcher(username) {
8176181819
return {
81762-
check: (user) => user.profile?.real_name?.toLowerCase() === username.toLowerCase(),
81820+
check: (user) => {
81821+
const realName = user.profile?.real_name?.toLowerCase() ?? '';
81822+
const usernameLower = username.toLowerCase();
81823+
return realName.includes(usernameLower) || usernameLower.includes(realName);
81824+
},
8176381825
description: 'user.profile.real_name fields',
8176481826
log: (user) => {
8176581827
(0,core.debug)(`Match found by username [${username}] matching Slack realName [${user.profile?.real_name}]`);
81828+
(0,core.debug)(`Redacted debug info: username [${redact(username)}] matched with real_name [${redact(user.profile?.real_name ?? '')}]`);
8176681829
},
8176781830
};
8176881831
}
81832+
/**
81833+
* Redacts a single word or part by replacing characters with random
81834+
* alphanumeric chars of the same case, preserving first and last character
81835+
*/
81836+
function redactPart(text) {
81837+
if (text.length <= 2) {
81838+
return text;
81839+
}
81840+
// Keep first and last characters intact
81841+
const first = text[0];
81842+
const last = text[text.length - 1];
81843+
const middle = text.substring(1, text.length - 1);
81844+
// Replace each middle character with a random one of the same case
81845+
const redactedMiddle = Array.from(middle)
81846+
.map((char) => {
81847+
// Skip non-alphanumeric characters
81848+
if (!/[a-zA-Z0-9]/.test(char)) {
81849+
return char;
81850+
}
81851+
// Generate substitutions based on character case
81852+
if (/[a-z]/.test(char)) {
81853+
return getRandomChar('abcdefghijklmnopqrstuvwxyz');
81854+
}
81855+
if (/[A-Z]/.test(char)) {
81856+
return getRandomChar('ABCDEFGHIJKLMNOPQRSTUVWXYZ');
81857+
}
81858+
if (/[0-9]/.test(char)) {
81859+
return getRandomChar('0123456789');
81860+
}
81861+
return char;
81862+
})
81863+
.join('');
81864+
return `${first}${redactedMiddle}${last}`;
81865+
}
8176981866
function userIdMatcher(userId) {
8177081867
return {
8177181868
check: (user) => user.id === userId,
8177281869
description: 'user.id fields',
8177381870
log: (user) => {
8177481871
(0,core.debug)(`Match found by userId [${userId}] with Slack userId [${user.id}]`);
81872+
(0,core.debug)(`Redacted debug info: userId matched with Slack userId [${redact(user.id ?? '')}]`);
8177581873
},
8177681874
};
8177781875
}
@@ -81782,6 +81880,7 @@ const createUserMatchers = ({ email, userId, userMappings = [], username }) => {
8178281880
const matchingMappings = userMappings.filter((mapping) => mapping.githubUsername === username);
8178381881
if (matchingMappings.length > 0) {
8178481882
(0,core.debug)(`Found [${matchingMappings.length}] custom mappings for GitHub username [${username}]`);
81883+
(0,core.debug)(`Redacted debug info: Found [${matchingMappings.length}] custom mappings for GitHub username [${redact(username)}]`);
8178581884
// Add a matcher for each mapping
8178681885
matchingMappings.forEach((mapping) => {
8178781886
matchers.push(customMappingMatcher(username, mapping.slackUsername));
@@ -81804,25 +81903,35 @@ const createUserMatchers = ({ email, userId, userMappings = [], username }) => {
8180481903
};
8180581904
const logFailedMatches = ({ email, userId, userMappings = [], username }, usersCount) => {
8180681905
console.log(`No user match found for [${username}] after checking against [${usersCount}] Slack ${(0,src.plural)('user', usersCount)}`);
81906+
// Redacted version
81907+
console.log(`Redacted debug info: No user match found for [${redact(username ?? '')}] after checking against [${usersCount}] Slack ${(0,src.plural)('user', usersCount)}`);
8180781908
// Log mapping failures
8180881909
if (username && userMappings.length > 0) {
8180981910
const matchingMappings = userMappings.filter((mapping) => mapping.githubUsername === username);
8181081911
if (matchingMappings.length > 0) {
8181181912
(0,core.debug)(`WARNING: Custom mappings for GitHub username [${username}] were defined but no matching Slack users were found:`);
81913+
(0,core.debug)(`Redacted debug info: WARNING: Custom mappings for GitHub username [${redact(username)}] were defined but no matching Slack users were found:`);
8181281914
// Show each mapping that failed
8181381915
matchingMappings.forEach((mapping) => {
8181481916
(0,core.debug)(` - Mapped to Slack username [${mapping.slackUsername}] but no Slack user with this name/display_name/real_name was found`);
81917+
(0,core.debug)(` - Redacted debug info: Mapped to Slack username [${redact(mapping.slackUsername)}] but no Slack user with this name/display_name/real_name was found`);
8181581918
});
8181681919
(0,core.debug)(`Attempted to fall back to standard matching methods`);
8181781920
}
8181881921
}
8181981922
// Log standard matchers that were tried
81820-
if (userId)
81923+
if (userId) {
8182181924
(0,core.debug)(`Tried to match userId [${userId}] against Slack user.id fields`);
81822-
if (email)
81925+
(0,core.debug)(`Redacted debug info: Tried to match userId [${redact(userId)}] against Slack user.id fields`);
81926+
}
81927+
if (email) {
8182381928
(0,core.debug)(`Tried to match email [${email}] against Slack user.profile.email fields`);
81824-
if (username)
81929+
(0,core.debug)(`Redacted debug info: Tried to match email [${redact(email)}] against Slack user.profile.email fields`);
81930+
}
81931+
if (username) {
8182581932
(0,core.debug)(`Tried to match username [${username}] against Slack user.profile.email (contains), display_name and real_name fields`);
81933+
(0,core.debug)(`Redacted debug info: Tried to match username [${redact(username)}] against Slack user.profile.email (contains), display_name and real_name fields`);
81934+
}
8182681935
(0,core.debug)(`Since no Slack user match found, unable to @mention user or use their profile image`);
8182781936
};
8182881937

@@ -90631,7 +90740,7 @@ module.exports = {"version":"3.17.0"};
9063190740
/***/ 8330:
9063290741
/***/ ((module) => {
9063390742

90634-
module.exports = /*#__PURE__*/JSON.parse('{"UU":"@krauters/github-notifier","rE":"1.3.2","TB":"https://buymeacoffee.com/coltenkrauter"}');
90743+
module.exports = /*#__PURE__*/JSON.parse('{"UU":"@krauters/github-notifier","rE":"1.3.3","TB":"https://buymeacoffee.com/coltenkrauter"}');
9063590744

9063690745
/***/ })
9063790746

dist/index.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@krauters/github-notifier",
33
"description": "GitHub Notifier by Krauters – Post Open Pull Requests to Slack",
4-
"version": "1.3.2",
4+
"version": "1.3.3",
55
"author": "Colten Krauter <coltenkrauter>",
66
"type": "module",
77
"homepage": "https://buymeacoffee.com/coltenkrauter",

0 commit comments

Comments
 (0)