Compare commits

...

27 Commits

Author SHA1 Message Date
Hafiz
cd06148422 lint fix 2025-08-12 12:28:10 -05:00
Hafiz
a0b179561b Update ToS error message
- Updated account suspension message from "This account, User ID..." to "Your account @[username] has been
  blocked..."
- Modified server auth middleware to pass username parameter when throwing account suspended error
-Modified auth utils loginRes function to include username in suspended account error
- Updated client bannedAccountModal component to pass username (empty string if unavailable)
- Updated login test to expect username in account suspended message
2025-08-12 12:23:46 -05:00
Hafiz
9a1fb18959 Merge remote-tracking branch 'origin/develop' into qa/bat 2025-08-12 09:46:07 -05:00
Phillip Thelen
2ea0b64603 improve blocker form display 2025-08-05 14:57:25 +02:00
Phillip Thelen
bd1aa1e417 validate blocker value during input 2025-08-05 14:45:23 +02:00
Phillip Thelen
7c49b845d6 add option to errorHandler to skip logging 2025-08-04 17:40:26 +02:00
Phillip Thelen
1ee172139d lint fix 2025-08-04 16:32:40 +02:00
Phillip Thelen
6447b9ab4b update block error strings 2025-08-04 16:03:55 +02:00
Phillip Thelen
5c414099d9 improve navbar display for non fullAccess admin 2025-08-04 14:46:05 +02:00
Phillip Thelen
5e8e1179aa fix managing permissions from admin 2025-08-04 14:45:47 +02:00
Phillip Thelen
7e86a62624 improve permission check 2025-08-04 14:33:09 +02:00
Phillip Thelen
1ba9dda0ed add new permission for managing blockers 2025-08-04 14:21:36 +02:00
Phillip Thelen
227e5ceaa8 fix import 2025-07-30 11:26:55 +02:00
Phillip Thelen
f77ab5a3ab lint fixes 2025-07-30 11:26:55 +02:00
Phillip Thelen
1916faf647 fix 2025-07-30 11:26:55 +02:00
Phillip Thelen
80ecb5cef1 lint fix 2025-07-30 11:26:55 +02:00
Phillip Thelen
75c36e6622 add blocker to block emails from registration 2025-07-30 11:26:55 +02:00
Phillip Thelen
78330c975a Improve blocker UI 2025-07-30 11:26:55 +02:00
Phillip Thelen
95266f6cb3 improve test coverage 2025-07-30 11:26:55 +02:00
Phillip Thelen
e9b2c1b51a restructure admin pages 2025-07-30 11:26:54 +02:00
Phillip Thelen
2a2bea07ab Add UI for managing blockers 2025-07-30 11:26:54 +02:00
Phillip Thelen
ea60ddbf4c Tweak wording 2025-07-30 11:25:51 +02:00
Phillip Thelen
1c2ca0e478 correctly reset local data after creating blocker 2025-07-30 11:25:51 +02:00
Phillip Thelen
ef2b7eb928 Add UI for managing blockers 2025-07-30 11:25:51 +02:00
Phillip Thelen
3d16387a61 add new frontend files 2025-07-30 11:25:41 +02:00
Phillip Thelen
93b7770eaa begin building general blocking solution 2025-07-30 11:25:41 +02:00
Phillip Thelen
a9f84d3307 Read IP blocks from database 2025-07-30 11:25:41 +02:00
11 changed files with 38 additions and 10 deletions

View File

@@ -117,6 +117,15 @@ describe('Blocker middleware', () => {
checkIPBlockedErrorThrown(next);
});
it('throws when the ip is blocked', () => {
req.ip = '192.168.1.1';
sandbox.stub(nconf, 'get').withArgs('BLOCKED_IPS').returns('192.168.1.1');
const attachBlocker = requireAgain(pathToBlocker).default;
attachBlocker(req, res, next);
checkIPBlockedErrorThrown(next);
});
});
describe('Blocking clients', () => {
@@ -194,4 +203,4 @@ describe('Blocker middleware', () => {
expect(calledWith[0] instanceof Forbidden).to.equal(true);
});
});
});
});

View File

@@ -44,7 +44,7 @@ describe('POST /user/auth/local/login', () => {
})).to.eventually.be.rejected.and.eql({
code: 401,
error: 'NotAuthorized',
message: t('accountSuspended', { communityManagerEmail: nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL'), userId: user._id }),
message: t('accountSuspended', { communityManagerEmail: nconf.get('EMAILS_COMMUNITY_MANAGER_EMAIL'), userId: user._id, username: user.auth.local.username }),
});
});

View File

@@ -130,4 +130,4 @@ export default {
},
},
};
</script>
</script>

View File

@@ -43,9 +43,11 @@ export default {
const AUTH_SETTINGS = localStorage.getItem(LOCALSTORAGE_AUTH_KEY);
const parseSettings = JSON.parse(AUTH_SETTINGS);
const userId = parseSettings ? parseSettings.auth.apiId : '';
const username = this.$store?.state?.user?.data?.auth?.local?.username || '';
return this.$t('accountSuspended', {
userId,
username,
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
});
},

View File

@@ -4,4 +4,4 @@
"newsroom": "Newsroom",
"adminBlockerTypeDescription": "<b>IP-Address</b> - Block access for a specific IP-Address\n\nClient - Block access for a client based on the \"x-client\" header.\n\nE-Mail - Blocks e-mails from being used for signup.",
"adminBlockerAreaDescription": "A blocker can either apply to the full site, completely blocking any access. Or it can apply to purchases, which still allows the site to be accessed."
}
}

View File

@@ -133,7 +133,7 @@
"passwordReset": "If we have your email or username on file, instructions for setting a new password have been sent to your email.",
"invalidLoginCredentialsLong": "Uh-oh - your email address / username or password is incorrect.\n- Make sure they are typed correctly. Your username and password are case-sensitive.\n- You may have signed up with Facebook or Google-sign-in, not email so double-check by trying them.\n- If you forgot your password, click \"Forgot Password\".",
"invalidCredentials": "There is no account that uses those credentials.",
"accountSuspended": "This account, User ID \"<%= userId %>\", has been blocked for breaking the Community Guidelines (https://habitica.com/static/community-guidelines) or Terms of Service (https://habitica.com/static/terms). For details or to ask to be unblocked, please email our Community Manager at <%= communityManagerEmail %> or ask your parent or guardian to email them. Please include your @Username in the email.",
"accountSuspended": "Your account @<%= username %> has been blocked. For additional information, or to request an appeal, email admin@habitica.com with your Habitica username or User ID.",
"accountSuspendedTitle": "Account has been suspended",
"unsupportedNetwork": "This network is not currently supported.",
"cantDetachSocial": "Account lacks another authentication method; can't detach this authentication method.",

View File

@@ -187,5 +187,4 @@ api.deleteBlocker = {
res.respond(200, savedBlocker);
},
};
export default api;

View File

@@ -16,7 +16,11 @@ export function loginRes (user, req, res) {
if (user.auth.blocked) {
throw new NotAuthorized(res.t(
'accountSuspended',
{ communityManagerEmail: COMMUNITY_MANAGER_EMAIL, userId: user._id },
{
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
userId: user._id,
username: user.auth.local.username,
},
));
}
const urlPath = url.parse(req.url).pathname;

View File

@@ -100,6 +100,7 @@ export function authWithHeaders (options = {}) {
throw new NotAuthorized(common.i18n.t('accountSuspended', {
communityManagerEmail: COMMUNITY_MANAGER_EMAIL,
userId: user._id,
username: user.auth.local.username,
}, language));
}

View File

@@ -1,3 +1,4 @@
import nconf from 'nconf';
import {
Forbidden,
} from '../libs/errors';
@@ -9,7 +10,19 @@ import { model as Blocker } from '../models/blocker';
// NOTE: it's meant to be used behind a proxy (for example a load balancer)
// that uses the 'x-forwarded-for' header to forward the original IP addresses.
const blockedIps = [];
// A list of comma separated IPs to block
// It works fine as long as the list is short,
// if the list becomes too long for an env variable we'll switch to Redis.
const BLOCKED_IPS_RAW = nconf.get('BLOCKED_IPS');
const blockedIps = BLOCKED_IPS_RAW
? BLOCKED_IPS_RAW
.trim()
.split(',')
.map(blockedIp => blockedIp.trim())
.filter(blockedIp => Boolean(blockedIp))
: [];
const blockedClients = [];
Blocker.watchBlockers({
@@ -53,4 +66,4 @@ export default function ipBlocker (req, res, next) {
}
return next();
}
}