Compare commits

...

28 Commits

Author SHA1 Message Date
Hafiz
17caa2159d missed add new line 2025-08-19 15:00:51 -05:00
Hafiz
36520ae6a5 lint 2025-08-19 14:55:59 -05:00
Hafiz
315a942c69 remove redundant disabled styles in task modals
The .disabled class conflicting with existing disabled state implementations
2025-08-19 14:48:26 -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
6 changed files with 37 additions and 14 deletions

View File

@@ -117,6 +117,15 @@ describe('Blocker middleware', () => {
checkIPBlockedErrorThrown(next); 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', () => { describe('Blocking clients', () => {

View File

@@ -35,7 +35,7 @@
</button> </button>
<button <button
class="btn btn-secondary d-flex align-items-center justify-content-center" class="btn btn-secondary d-flex align-items-center justify-content-center"
:class="{disabled: !canSave}" :class="{'btn-disabled': !canSave}"
type="button" type="button"
@click="submit()" @click="submit()"
> >
@@ -162,13 +162,13 @@
> >
<div <div
class="habit-option-icon svg-icon no-transition" class="habit-option-icon svg-icon no-transition"
:class="task.up ? '' : 'disabled'" :class="task.up ? '' : 'icon-disabled'"
v-html="icons.positive" v-html="icons.positive"
></div> ></div>
</div> </div>
<div <div
class="habit-option-label no-transition" class="habit-option-label no-transition"
:class="task.up ? cssClass('icon') : 'disabled'" :class="task.up ? cssClass('icon') : 'label-disabled'"
> >
{{ $t('positive') }} {{ $t('positive') }}
</div> </div>
@@ -188,13 +188,13 @@
> >
<div <div
class="habit-option-icon no-transition svg-icon negative mx-auto" class="habit-option-icon no-transition svg-icon negative mx-auto"
:class="task.down ? '' : 'disabled'" :class="task.down ? '' : 'icon-disabled'"
v-html="icons.negative" v-html="icons.negative"
></div> ></div>
</div> </div>
<div <div
class="habit-option-label no-transition" class="habit-option-label no-transition"
:class="task.down ? cssClass('icon') : 'disabled'" :class="task.down ? cssClass('icon') : 'label-disabled'"
> >
{{ $t('negative') }} {{ $t('negative') }}
</div> </div>
@@ -592,7 +592,7 @@
<button <button
class="btn btn-primary btn-footer class="btn btn-primary btn-footer
d-flex align-items-center justify-content-center" d-flex align-items-center justify-content-center"
:class="{disabled: !canSave}" :class="{'btn-disabled': !canSave}"
type="button" type="button"
@click="submit()" @click="submit()"
> >
@@ -881,12 +881,14 @@
} }
} }
.disabled { .btn-disabled {
background-color: $white; background-color: $white;
border: 2px solid transparent; border: 2px solid transparent;
color: $gray-200; color: $gray-200;
line-height: 1.714; line-height: 1.714;
box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24); box-shadow: 0px 1px 3px 0px rgba(26, 24, 29, 0.12), 0px 1px 2px 0px rgba(26, 24, 29, 0.24);
cursor: not-allowed;
opacity: 0.6;
&:focus { &:focus {
background-color: $white; background-color: $white;
@@ -948,7 +950,7 @@
height: 10px; height: 10px;
color: $white; color: $white;
&.disabled { &.icon-disabled {
color: $gray-200; color: $gray-200;
} }
@@ -962,7 +964,7 @@
font-weight: bold; font-weight: bold;
text-align: center; text-align: center;
&.disabled { &.label-disabled {
color: $gray-100; color: $gray-100;
font-weight: normal; font-weight: normal;
} }
@@ -1018,7 +1020,7 @@
border: 0; border: 0;
} }
.disabled .input-group-text { .input-group-outer.disabled .input-group-text {
color: $gray-200; color: $gray-200;
} }

View File

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

View File

@@ -1,3 +1,4 @@
import nconf from 'nconf';
import { import {
Forbidden, Forbidden,
} from '../libs/errors'; } 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) // 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. // 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 = []; const blockedClients = [];
Blocker.watchBlockers({ Blocker.watchBlockers({