Skip to content

Commit e1bf33c

Browse files
Preps for 2.0-RC5
1 parent e469abb commit e1bf33c

File tree

92 files changed

+1790
-772
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+1790
-772
lines changed

Makefile

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ recommendation_dev:
6666
recommendation_release:
6767
go generate -tags="release" gitlab.com/lightmeter/controlcenter/recommendation
6868

69-
mocks: postfix_parser dashboard_mock insights_mock detective_mock intel_mock
69+
mocks: postfix_parser dashboard_mock insights_mock detective_mock intel_mock timeutil_mock
7070

7171
dashboard_mock:
7272
go generate -tags="dev" gitlab.com/lightmeter/controlcenter/dashboard
@@ -77,6 +77,9 @@ insights_mock:
7777
intel_mock:
7878
go generate -tags="dev" gitlab.com/lightmeter/controlcenter/intel/receptor
7979

80+
timeutil_mock:
81+
go generate -tags="dev" gitlab.com/lightmeter/controlcenter/util/timeutil
82+
8083
detective_mock:
8184
go generate -tags="dev sqlite_json" gitlab.com/lightmeter/controlcenter/detective
8285

@@ -109,9 +112,6 @@ clean_mocks:
109112
dependencies.svg: go.sum go.mod
110113
go mod graph | tools/gen_deps_graph.py | dot -Tsvg > dependencies.svg
111114

112-
make testlocal:
113-
./tools/go_test_local.sh
114-
115115
postfix_parser:
116116
go generate gitlab.com/lightmeter/controlcenter/pkg/postfix/logparser/rawparser
117117

README.md

Lines changed: 34 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -165,8 +165,8 @@ For more information about how the CA certificates are found, please check the c
165165
In case the logs directory passed via `-watch_dir` is not in the same filesystem as postfix writes them, but instead copied via rsync,
166166
you must pass the command line argument `-logs_use_rsync`, otherwise new log lines received after the first `rsync` execution won't be noticed.
167167

168-
When using rsync, remembed **NOT** to use any in-place synchronization option, such as `--append`, as Control Center expects the default rsync behaviour
169-
on updating files that consists on first create a temporary file in the destination and onde it's completely transfered, rename it to the final file.
168+
When using rsync, remember **NOT** to use any in-place synchronization option, such as `--append`, as Control Center expects the default rsync behaviour
169+
on updating files that consists on first create a temporary file in the destination and once it's completely transferred, rename it to the final file.
170170

171171
### Docker image
172172

@@ -178,7 +178,7 @@ $ docker run -p 8080:8080 -v "<path_to_workspace>:/workspace:rw" -v "/var/log/:/
178178
179179
```
180180

181-
Where `<path_to_workspace>` is a directory where Control Center will keep data that has to be persisted accross restarts.
181+
Where `<path_to_workspace>` is a directory where Control Center will keep data that has to be persisted across restarts.
182182

183183
Then open your browser on http://localhost:8080 to access the web based user interface.
184184

@@ -229,7 +229,7 @@ For detailed information, check [Usage](cli_usage.md).
229229
- The web UI authenticated sessions last 1 week by default
230230
- To supply logs via stdin instead of logfile location, use the command line argument `-stdin` like `lightmeter -stdin < [log-data]`.
231231
- You can also receive logs listening on an unix socket or a TCP port, as in `-socket "unix;/path/to/socket.sock"` or
232-
`-socket "tcp;localhost:9999"`. It's important to notice that such socket communication is unanthenticated and unencrypted, so use it only in safe environments!
232+
`-socket "tcp;localhost:9999"`. It's important to notice that such socket communication is unauthenticated and unencrypted, so use it only in safe environments!
233233
- To supply single logs file, use the command line argument `-stdin` like `tail -f /path-to-file.log | lightmeter -stdin`.
234234
- Mailserver data is stored in separate workspaces so that different servers can be monitored separately. The workspace directory is set as `/var/lib/lightmeter_workspace` by default and can be changed with `-workspace /path/to/workspace`.
235235
- As Postfix logs don't contain a year as part of the date of each line, when using `-stdin`, the year for processed logs is assumed to be the current one. To override this and specify a year manually, use the `-log_starting_year` flag like `-log_starting_year 2018`
@@ -434,21 +434,21 @@ Domain Mapping is supported. This means remote hosts which are related to each o
434434

435435
Currently the mapping is hardcoded in the application - changing the mappings requires [rebuilding](#Build-from-source-code) the application.
436436

437-
Mappings are stored in `domainmapping/mapping.json` and cover the largest remote hosts by default. The mappings can be easily customised by editing that file, followed by [rebuilding](#Build-from-source-code).
437+
Mappings are stored in `domainmapping/mapping.json` and cover the largest remote hosts by default. The mappings can be easily customized by editing that file, followed by [rebuilding](#Build-from-source-code).
438438

439439
Please consider extending the default mappings by making merge requests to benefit all users!
440440

441441
### Message Detective
442442

443443
#### Admin view
444444

445-
You can access the admin view for the message detective clicking the "Search" icon on the navigation bar.
446-
The Lightmeter admin can search for a given message by timeframe, sender, recipient, Postfix ID/message ID, or status, to troubleshoot email delivery.
445+
You can access the admin view for the message detective clicking the "Search" icon on the navigation bar.
446+
Using sender address, recipient address and the time interval you want to check, you can identify the status of any message processed in the given timeframe.
447447

448-
The search result will include the status of the message, the queue ID, the time the message was processed and the status code of each delivery attempt.
448+
The search result will include the status of the message, the queue ID, the time the message was processed and the status code of each delivery attempt.
449449

450-
A message can have one of the following states:
451-
- Sent for successfull delivery
450+
A message can have one of the following states:
451+
- Sent for successfully delivery
452452
- Bounced for messages refused by recipient's mail provider
453453
- Deferred for messages temporarily refused and retried
454454
- Expired for abandoned delivery after too many deferred attempts
@@ -457,13 +457,13 @@ A message can have one of the following states:
457457

458458
#### Public view
459459

460-
You can enable the message detective for any unauthenticated users in the Settings Page.
460+
You can enable the message detective for any unauthenticated users in the Settings Page.
461461

462-
Any user (whom you have provided the link to) can check the fate of a message independently, using the email addresses of the sender AND the recipient, and the message status. In the search results, they will see the same information per message as the admin.
462+
Any user (whom you have provided the link to) can check the fate of a message independently, using the same search terms as the admin. They will also see the same amount of information in the search results as the admin.
463463

464464
In addition, the user will also have the option to Escalate any Bounced and Expired results to the mail server admin.
465-
Lightmeter will then generate an insight that shows all the details, including queue ID for the admin to investigate further.
466-
If you have notifications enabled, this will also trigger a notification.
465+
Lightmeter will then generate an insight that shows all the details, including queue ID for the admin to investigate further.
466+
If you have notifications enabled, this will also trigger a notification.
467467

468468
If you enable the message detective for your end-users, make sure to share the public page URL with them.
469469
Rate limiting is applied on the number of searches, with a current maximum of 20 searches every 10 minutes.
@@ -476,66 +476,47 @@ Currently the network requires participation to access these features; to receiv
476476

477477
#### Brute force protection
478478

479-
Protection against malicious SMTP and IMAP login attempts requires access to a Dovecot server. Dovecot occupies the role of a convenient authentication policy client for both Postfix (SMTP) and Dovecot itself (IMAP).
479+
Protection against malicious SMTP and IMAP login attempts requires access to a Dovecot server. Dovecot occupies the role of a convenient authentication policy client for both Postfix (SMTP) and Dovecot itself (IMAP).
480480

481481
When enabled, both Dovecot and Postfix will use a Lightmeter blocklist (generated from real-time Peer Network signals) for pre-authentication checks.
482482

483483
Protection is not complete or guaranteed, and could theoretically result in legitimate authentication attempts being blocked.
484484

485485
##### Dovecot configuration
486486

487-
To enable blocking of malicious IPs in Dovecot (IMAP/POP defence), execute the following script:
487+
We provide a utility as part of controlcenter that generates some needed Dovecot configuration. If you are using Lightmeter in Docker,
488+
you can do it with the command:
488489

490+
```sh
491+
docker run -it --rm lightmeter/controlcenter:latest -dovecot_conf_gen > /path/to/etc/dovecot/conf.d/10-lightmeter.conf
489492
```
490-
#!/bin/sh
491-
492-
# setup lightmeter auth_policy server on dovecot
493-
494-
# TODO: check the dovecot path is correct
495-
cat << EOF > /etc/dovecot/conf.d/10-auth_lightmeter.conf
496-
497-
# Dovecot will query Lightmeter's blocklist for every incoming IMAP/POP3 connection
498-
auth_policy_server_url = https://auth.intelligence.lightmeter.io/auth
499-
500-
# TODO: replace the following by a random string of your own
501-
# See https://doc.dovecot.org/settings/core/#setting-auth-policy-hash-nonce for more information
502-
auth_policy_hash_nonce = JHghjghHJGhjg$345gfGF35435
503-
504-
# The remote IP address, that is trying to authenticate, is the minimal bit of information
505-
# needed by Lightmeter to block illegitimate authentication attempts
506-
# See https://doc.dovecot.org/settings/core/#setting-auth-policy-request-attributes for more information
507-
auth_policy_request_attributes = remote=%{rip}
508-
509-
# Check Lightmeter blocklist before auth (pre-auth), not after
510-
# Also, report un·successful auth attempts
511-
auth_policy_check_before_auth = yes
512-
auth_policy_check_after_auth = no
513-
auth_policy_report_after_auth = yes
514493

515-
# The following is needed to verify the number of blocked auth attempts
516-
auth_verbose = yes
517-
EOF
494+
Or, similarly, when using the standalone binary:
518495

519-
dovecot reload
496+
```sh
497+
/path/to/lightmeter -dovecot_conf_gen > /etc/dovecot/conf.d/10-lightmeter.conf
520498
```
521499

500+
And finally, reload the Dovecot configuration with `doveconf reload` to apply those changes.
501+
522502
###### Older Dovecot version
523503

524-
In case you're running a version of Dovecot older than 2.3.1, you will experience that the `auth_policy_check_before_auth` parameter does not exist.
504+
If your Dovecot version is older than 2.3.1, you need to pass an extra argument `-dovecot_conf_is_old`, as in:
525505

526-
If this is the case, leave out these three parameters from the above configuration file:
527-
- `auth_policy_check_before_auth`
528-
- `auth_policy_check_after_auth`
529-
- `auth_policy_report_after_auth`
506+
```sh
507+
/path/to/lightmeter -dovecot_conf_gen -dovecot_conf_is_old > /etc/dovecot/conf.d/10-lightmeter.conf
508+
```
530509

531510
The counting of blocked IPs will be doubled in your Control Center¹, but you'll still enjoy protection (¹ we're trying to find a workaround).
532511

533-
534512
##### Postfix configuration
535513

536-
To enable blocking of malicious IPs by Postfix (SMTP defence) do the following.
514+
To enable blocking of malicious IPs by Postfix (SMTP defense) do the following.
515+
516+
Use Dovecot SASL to pre-authorize connection attempts.
537517

538-
Use Dovecot SASL to pre-authorize connection attempts. Note: if Postfix is already configured to use SASL, this will replace it.
518+
**Note**: if Postfix is already configured to use SASL, this will replace it. This configuration works only if Postfix and Dovecot share the same filesystem.
519+
For more complex setups, please contact us at hello AT lightmeter.io.
539520

540521
If Dovecot is not already being used as a SASL server, add this to your Dovecot config file (e.g. `/etc/dovecot/conf.d/10-auth.conf`):
541522

@@ -616,7 +597,7 @@ The following command will look for translatable words inside interface files (c
616597

617598
Translatable strings can be found in diverse files, such as Go code, used by the backend, or Vue/html/js files used in the web ui.
618599

619-
In order to update the translable strings, making them available for translators with the command:
600+
In order to update the translatable strings, making them available for translators with the command:
620601

621602
```bash
622603
$ make messages

acceptance_tests/package-lock.json

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

acceptance_tests/specs/1_1_registration.spec

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Tags: failure
77
* Focus on field with placeholder "Name"
88
* Type "User Complete Name"
99
* Focus on field with placeholder "Email"
10-
* Type "acceptance_tests@lightmeter.io"
10+
* Type "not an email"
1111
* Focus on field with placeholder "Password"
1212
* Type "54353%#%#54354353gffgdgdfg"
1313
* Expect registration to fail
@@ -23,6 +23,5 @@ Tags: success
2323
* Type "acceptance_tests@lightmeter.io"
2424
* Focus on field with placeholder "Password"
2525
* Type "54353%#%#54354353gffgdgdfg"
26-
* Select option "direct" from menu "Most of my mail is…"
2726
* Click on "Register"
2827
* Expect to be in the main page
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Message Detective admin view
2+
3+
Search for messages
4+
5+
## Search results
6+
7+
* Go to detective
8+
* Expect to see "Message Detective"
9+
10+
* Datepicker last 3 months
11+
* Click on "Search"
12+
13+
* Expect "1" detective results
14+
* Expect to see "Sent"
15+
* Expect to see "sender@sender.example.com"
16+
* Expect to see "user@recipient.example.com"
17+
* Expect to see "1F5A2194AA9"
18+
* Expect to see "AFFBE802-D6B1-483C-ABE2-783F531DE68B@example.com"

acceptance_tests/tests/step_implementation.js

Lines changed: 57 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const assert = require("assert");
3131
const child_process = require("child_process")
3232
const tmp = require("tmp")
3333
const path = require("path")
34+
const fs = require('fs');
3435

3536
tmp.setGracefulCleanup();
3637

@@ -40,20 +41,48 @@ var lightmeterProcess = null
4041

4142
var workspaceDir = tmp.dirSync()
4243

44+
function getLogsWithSingleDateTodayMinus45Days(originalLogFile) {
45+
let logs = "";
46+
try {
47+
const data = fs.readFileSync(originalLogFile, 'utf8');
48+
const lines = data.split(/\r?\n/);
49+
50+
let somePreviousMonth = new Date(new Date() - 45 *1000*3600*24); // now - 45 days
51+
let prevDate = somePreviousMonth.toISOString().substring(0,11);
52+
53+
lines.forEach((line) => {
54+
line = line.replace( new RegExp("^\\d{4}-\\d{2}-\\d{2}T"), prevDate)
55+
logs += line + "\n"
56+
});
57+
}
58+
catch (err) {
59+
console.error(err);
60+
}
61+
62+
return logs;
63+
}
64+
4365
beforeSuite(async () => {
44-
let callback = function(error, stdout, stderr) {
45-
if (error) {
46-
console.warn(stdout)
47-
console.error(stderr)
48-
throw error
49-
}
66+
let callback = function(error, stdout, stderr) {
67+
if (error) {
68+
console.warn(stdout)
69+
console.error(stderr)
70+
throw error
5071
}
72+
}
5173

52-
lightmeterProcess = child_process.execFile('../lightmeter', ['-workspace', workspaceDir.name, '-stdin', '-listen', ':8080'], callback)
74+
lightmeterProcess = child_process.execFile(
75+
'../lightmeter',
76+
['-workspace', workspaceDir.name, '-stdin', '-log_format', 'rfc3339', '-listen', ':8080'],
77+
callback
78+
)
5379

54-
return new Promise((r) => setTimeout(r, 2000)).then(async () => {
55-
await openBrowser({ headless: headless, args: ["--no-sandbox", "--no-first-run"] })
56-
})
80+
let logs = getLogsWithSingleDateTodayMinus45Days('../test_files/postfix_logs/individual_files/25_authclean_cleanup.log');
81+
lightmeterProcess.stdin.write(logs)
82+
83+
return new Promise((r) => setTimeout(r, 2000)).then(async () => {
84+
await openBrowser({ headless: headless, args: ["--no-sandbox", "--no-first-run"] })
85+
})
5786
});
5887

5988
step("Expect registration to fail", async () => {
@@ -95,6 +124,11 @@ step("Go to login page", async () => {
95124
await reload(waitOpt)
96125
});
97126

127+
step("Go to detective", async () => {
128+
await goto('http://localhost:8080/#/detective', waitOpt);
129+
await reload(waitOpt)
130+
});
131+
98132
step("Focus on field with placeholder <placeholder>", async (placeholder) => {
99133
await focus(textBox({placeholder: placeholder}))
100134
});
@@ -107,6 +141,7 @@ step("Type <content>", async (content) => {
107141
await write(content)
108142
});
109143

144+
// NOTE: not used any more, was used for mailKind dropdown
110145
step("Select option <option> from menu <menuName>", async (option, menuName) => {
111146
// Ugly workaroudn due a bug on taiko: https://github.com/getgauge/taiko/issues/1729
112147
//await dropDown(menuName).select(option)
@@ -138,15 +173,20 @@ step("Set start date", async () => {
138173
});
139174

140175
step("Move forward some months", async () => {
141-
var button = $(".daterangepicker * .right * .next")
176+
var button = $(".daterangepicker * .left * .next")
142177

143178
for (var i = 0; i < 3; i++) {
144179
await click(button)
145180
}
146181
});
147182

148183
step("Set end date", async () => {
149-
await click($(".daterangepicker * .right * td.weekend"))
184+
await click($(".daterangepicker * .left * td.weekend"))
185+
});
186+
187+
step("Datepicker last 3 months", async () => {
188+
await click($(".vue-daterange-picker"))
189+
await click(text('Last 3 months (all time)'))
150190
});
151191

152192
step("Click logout", async () => {
@@ -155,7 +195,7 @@ step("Click logout", async () => {
155195
});
156196

157197
step("Expect to see <pageText>", async (pageText) => {
158-
await text(pageText).exists()
198+
await assert.ok(await text(pageText).exists())
159199
});
160200

161201
step("Expect to be in the main page", async () => {
@@ -165,3 +205,7 @@ step("Expect to be in the main page", async () => {
165205
return url == "http://localhost:8080/#/";
166206
})
167207
});
208+
209+
step("Expect <x> detective results", async (x) => {
210+
assert.equal( (await $('.results .detective-result-cell').elements()).length, 1);
211+
});

0 commit comments

Comments
 (0)