Commit Graph

63 Commits

Author SHA1 Message Date
Simone Basso
6aa2551c43
urlgetter: fix tunnel test (#299)
* urlgetter: fix tunnel test

This diff fixes the urlgetter test suite to make sure we
are correctly testing for tunnel creation.

While there, improve the way in which we create a testing
directory and add a test for that.

Part of https://github.com/ooni/probe/issues/985.

* fix comment

* fix comment
2021-04-05 18:25:43 +02:00
Simone Basso
973501dd11
feat(tunnel): implement the fake tunnel (#298)
This functionality should be helpful to test that the general
interface of the tunnel package is okay from the engine package.

Part of https://github.com/ooni/probe/issues/985
2021-04-05 17:41:15 +02:00
Simone Basso
76a50facc3
feat(tunnel): improve the test suite (#297)
Part of https://github.com/ooni/probe/issues/985
2021-04-05 16:38:25 +02:00
Simone Basso
2bafb179c3
refactor(tunnel): remove nil tunnels hack (#296)
* refactor(tunnel): remove nil tunnels hack

This code was originally introduced because a tunnel could be
nil in session.go. I have verified that every invocation of
tunnel.Start is careful to ensure that we have a tunnel name
and that we don't manipulate a nil tunnel.

For this reason, I'd rather remove this tricky bit of code and
further simplify the tunnel code.

Part of https://github.com/ooni/probe/issues/985

* even better docs
2021-04-05 16:08:16 +02:00
Simone Basso
c5ad5eedeb
feat: create tunnel inside NewSession (#286)
* feat: create tunnel inside NewSession

We want to create the tunnel when we create the session. This change
allows us to nicely ignore the problem of creating a tunnel when we
already have a proxy, as well as the problem of locking. Everything is
happening, in fact, inside of the NewSession factory.

Modify miniooni such that --tunnel is just syntactic sugar for
--proxy, at least for now. We want, in the future, to teach the
tunnel to possibly use a socks5 proxy.

Because starting a tunnel is a slow operation, we need a context in
NewSession. This causes a bunch of places to change. Not really a big
deal except we need to propagate the changes.

Make sure that the mobile code can create a new session using a
proxy for all the APIs we support.

Make sure all tests are still green and we don't loose coverage of
the various ways in which this code could be used.

This change is part of https://github.com/ooni/probe/issues/985.

* changes after merge

* fix: only keep tests that can hopefully work

While there, identify other places where we should add more
tests or fix integration tests.

Part of https://github.com/ooni/probe/issues/985
2021-04-05 15:28:13 +02:00
Simone Basso
a849213b59
fix(engine): break circular dep betwen session and tunnel (#295)
This diff breaks the circular dependency between session and
tunnel, by introducing the concept of early session.

An early session is a session that is able to fetch the psiphon
configuration file _only_ if it's embedded in the binary.

This breaks `miniooni --tunnel=psiphon` for users who have
access to the OONI backend. They are not the users we are
writing this feature for, though, so I think this is reasonable.

At the same time, this opens up the possibility of creating
a psiphon tunnel when constructing a session, which is the
approach I was following in https://github.com/ooni/probe-cli/pull/286.

This work is part of https://github.com/ooni/probe/issues/985.

Once this diff is in, I can land https://github.com/ooni/probe-cli/pull/286.
2021-04-05 12:02:35 +02:00
Simone Basso
8fe4e5410d
feat(tunnel): introduce persistent tunnel state dir (#294)
* feat(tunnel): introduce persistent tunnel state dir

This diff introduces a persistent state directory for tunnels, so that
we can bootstrap them more quickly after the first time.

Part of https://github.com/ooni/probe/issues/985

* fix: make tunnel dir optional

We have many tests where it does not make sense to explicitly
provide a tunnel dir because we're not using tunnels.

This should simplify setting up a session.

* fix(tunnel): repair tests

* final changes

* more cleanups
2021-04-05 11:27:41 +02:00
Simone Basso
47aa773731
refactor(tunnel): provide TorArgs and TorBinary directly (#293)
We're trying to remove a circular dependency between the measurement
Session and the tunnel package. To this end, continue to reduce the
dependency scope by providing TorArgs and TorBinary directly.

Part of https://github.com/ooni/probe/issues/985
2021-04-04 12:08:13 +02:00
Simone Basso
1eb63bc4b6
refactor(tunnel): remove dependecy from logger (#292)
Part of https://github.com/ooni/probe/issues/985
2021-04-04 11:23:03 +02:00
Simone Basso
dae53cb2a2
fix(tunnel/psiphon): don't overwrite config.WorkDir (#291)
Part of https://github.com/ooni/probe/issues/985
2021-04-03 21:34:19 +02:00
Simone Basso
d9aff19be5
refactor(tunnel): simplify tor implementation (#290)
Simplify interaction within the package by avoiding to have
a tor specific config. Use a Config instead.

Part of https://github.com/ooni/probe/issues/985.
2021-04-03 21:25:08 +02:00
Simone Basso
f739450370
refactor(tunnel): simplify psiphon implementation (#289)
Simplify interaction within the package by avoiding to have
a psiphon specific config. Use a Config instead.

Part of https://github.com/ooni/probe/issues/985.
2021-04-03 21:09:34 +02:00
Simone Basso
b53290cbfe
refactor(tunnel): pass the config as a pointer (#288)
Part of https://github.com/ooni/probe/issues/985
2021-04-03 20:12:56 +02:00
Simone Basso
ecb2aae1e8
refactor: merge psiphonx and torx into tunnel (#287)
* refactor: merge psiphonx and torx into tunnel

This is a case where it seems that merging these three packages into
a single package will enable us to better the implementation.

The goal is still https://github.com/ooni/probe/issues/985.

The roadblock I'm trying to overcome is
https://github.com/ooni/probe-cli/pull/286#pullrequestreview-627460104.

* avoid duplicating logger for now
2021-04-03 19:57:21 +02:00
Simone Basso
d7cd1ebcaf
refactor(riseupvpn): minor changes and annotations (#275) 2021-04-02 17:58:36 +02:00
Simone Basso
c89ecce3e0
feat: support embedding encrypted psiphon config (#285)
We use an optional build tag to hide this configuration. When you
choose this configuration, you need to provide the encrypted config
as well as the corresponding decryption key.

This is not the final design. This is an interim design to start
working and experimenting with this functionality. The general
idea here is to support psiphon in the binaries we build without
committing the psiphon config to the repository itself.

Part of https://github.com/ooni/probe/issues/985
2021-04-02 17:36:06 +02:00
Simone Basso
79e8424677
refactor: remove model.ExperimentOrchestraClient (#284)
* ongoing

* while there, make sure we test everything

* reorganize previous commit

* ensure we have reasonable coverage in session

The code in here would be better with unit tests. We have too many
integration tests and the tests overall are too slow. But it's also
true that I should not write a giant diff as part of this PR.
2021-04-02 12:03:18 +02:00
Simone Basso
2ca9496c04
Release: update user-agent, bundled CA, version number (#281)
* chore: update the user-agent we use

Part of the check-list at https://github.com/ooni/probe/issues/1369.

* chore: set version to 3.9.0

See https://github.com/ooni/probe/issues/1369

* chore: run go generate ./...

This is meant to update the bundled CA. We have heard of issues with
our bundled CA, but it seems there have been no changes upstream.

The website https://curl.se/docs/caextract.html still lists as the
last change the one done on Jan 19, 2021, which is the version of
the CA that we're currently bundling.

For the sake of continuing with the release process, I am going
to further investigate the CA once the release is done.

This chore is part of https://github.com/ooni/probe/issues/1369.
2021-04-01 18:40:30 +02:00
Simone Basso
31e478b04e
refactor: redesign how we import assets (#260)
* fix(pkg.go.dev): import a subpackage containing the assets

We're trying to fix this issue that pkg.go.dev does not build.

Thanks to @hellais for this very neat idea! Let's keep our
fingers crossed and see whether it fixes!

* feat: use embedded geoip databases

Closes https://github.com/ooni/probe/issues/1372.

Work done as part of https://github.com/ooni/probe/issues/1369.

* fix(assetsx): add tests

* feat: simplify and just vendor uncompressed DBs

* remove tests that seems not necessary anymore

* fix: run go mod tidy

* Address https://github.com/ooni/probe-cli/pull/260/files#r605181364

* rewrite a test in a better way

* fix: gently cleanup the legacy assetsdir

Do not remove the whole directory with brute force. Just zap the
files whose name we know. Then attempt to delete the legacy directory
as well. If not empty, just fail. This is fine because it means the
user has stored other files inside the directory.

* fix: create .miniooni if missing
2021-04-01 16:57:31 +02:00
Simone Basso
7ca32b5ce6
release process: update dependencies (#280)
Part of the check-list at https://github.com/ooni/probe/issues/1369
2021-03-31 16:40:58 +02:00
Simone Basso
bd451016f5
release 3.9.0 process: reduce warnings (#279)
* fix(riseupvpn): address gofmt warning

Thanks to https://goreportcard.com/report/github.com/ooni/probe-cli.

* fix(utils.go): correct the docu-comment

Thanks to https://goreportcard.com/report/github.com/ooni/probe-cli

* fix: improve spelling

Thanks to https://goreportcard.com/report/github.com/ooni/probe-cli

* fix(modelx_test.go): avoid inefassign warning

Thanks to https://goreportcard.com/report/github.com/ooni/probe-cli

* fix: reduce number of ineffective assignments

Thanks to https://goreportcard.com/report/github.com/ooni/probe-cli
2021-03-31 15:59:19 +02:00
cyBerta
991b0a6120
riseupvpn: reduce false positives (#233)
* fetch RiseupVPN CA cert with MultiGetter. It allows us to write better tests and ensures this test step is added in the logs

* Implement TransportStatus for RiseupVPN tests. It indicates if a whole transport is blocked, which is considered as a test anomaly

* Redesign unit tests for RiseupVPN. Instead of a real backend, mocked server responses are used. Tests for invalid CA certs and for TransportStatus are added.

* Update internal/engine/experiment/riseupvpn/riseupvpn.go

Co-authored-by: Simone Basso <bassosimone@gmail.com>
2021-03-30 12:02:51 +02:00
Simone Basso
a0763756b2
fix(miniooni): replace --limit with --max-runtime (#272)
Part of https://github.com/ooni/probe/issues/1299
2021-03-29 20:38:23 +02:00
Simone Basso
b718335ee3
refactor(inputloader): remove unnecessary javisms (#271)
Part of https://github.com/ooni/probe/issues/1299.
2021-03-29 20:00:50 +02:00
Simone Basso
1da64f6d9f
fix(internal/fsx): remove pre Go 1.16 definitions (#270)
Occurred to me while working on https://github.com/ooni/probe/issues/1299.
2021-03-29 19:37:32 +02:00
Simone Basso
87e5234586
refactor(inputloader): all fast tests together (#269)
This change allows us to have all fasts tests together. They are
mostly unit tests or integration tests that do not require the
network. The advantage of this strategy is the following. We can
now run all these tests with a single click in VSCode. In turn,
doing that tells us which lines of code we are not covering.

The tests requiring the network are in a separate file, so we can
easily see which lines of code are testing without using the network
and which ones instead depend on that. (Currently, 100% of the
inputloader.go file is tested without using the network.)

While there, rename the other file such that is clear that it
contains tests requiring the network. We now have some tests in
inputloader_test.go that are not strictly unit tests.

This refactoring was identified as useful while working
on https://github.com/ooni/probe/issues/1299.
2021-03-29 19:19:06 +02:00
Simone Basso
5973c88a05
feat(inputloader): use check-in to fetch URLs (#267)
* ongoing work

* reduce diff with master

* feat(inputloader): use the check-in API

Part of https://github.com/ooni/probe/issues/1299

* fix: better naming for a variable

* chore: add more tests

* fix: add one more TODO
2021-03-29 18:46:26 +02:00
Simone Basso
e0b0dfedc1
feat(session): expose CheckIn method (#266)
* feat(session): expose CheckIn method

It seems to me the right thing to do is to query the CheckIn API
from the Session rather than querying it from InputLoader.

Then, InputLoader could just take a reference to a Session-like
interface that allows this functionality.

So, this diff exposes the Session.CheckIn method.

Doing that, in turn, required some refactoring to allow for
more and better unit tests.

While doing that, I also noticed that Session required a mutex
to be a well-behaving type, so I did that.

While doing that, I also tried to cover all the lines in session.go
and, as part of that, I have removed unused code.

Reference issue: https://github.com/ooni/probe/issues/1299.

* fix: reinstate comment I shan't have removed

* fix: repair broken test

* fix: a bit more coverage, annotations, etc.

* Update internal/engine/session.go

* Update internal/engine/session_integration_test.go

* Update internal/engine/session_internal_test.go
2021-03-29 15:04:41 +02:00
Simone Basso
0115d6c470
refactor(inputloader): better docs and naming (#265)
* refactor(inputloader): better docs and naming

Work done as part of https://github.com/ooni/probe/issues/1299.

* fix: correct a typo
2021-03-26 09:34:27 +01:00
Simone Basso
c94721d9e5
fix(sessionresolver): proxy check conditional on existing proxy (#264)
There was a face-palming error in the implementation causing the proxy
check to be implemented also without a proxy.

This meant that we were ALWAYS skipping http3 and system resolvers.

The bug has been introduced in 3.8.0. So, the currently released
version of the probe, sadly, has this beheavior :-(.

Reference issue https://github.com/ooni/probe/issues/1426.
2021-03-25 15:18:29 +01:00
Simone Basso
3b029ee0d6
feat(ExperimentOrchestraClient): add CheckIn (#263)
We use ExperimentOrchestraClient in several places to help us
calling probe-services APIs. We need to call CheckIn because we
want to use CheckIn in InputLoader.

(We also want to remove the URLs API, but that is not something
doable now, since the mobile app is still using this API via
the wrappers at pkg/oonimkall.)

Work part of https://github.com/ooni/probe/issues/1299.
2021-03-25 12:02:02 +01:00
Simone Basso
576059b3fa
fix: apply staticcheck suggestions (#262)
Preliminary work done as part of https://github.com/ooni/probe/issues/1299
2021-03-24 12:35:53 +01:00
Simone Basso
fc19c9901a
fix(webconnectivity): expose network events (#258)
* fix(webconnectivity): expose network events

By not exposing network events in webconnectivity, we are missing
several interesting, explanatory data points.

This diff fixes the issue by:

1. enriching the definition of network events to include extra
data useful for performing (manual) data analysis;

2. adding a tags field to network events such that we can add
tags to specific events and understand where they come from;

3. exposing all the (tagged) network events that happen when running
a webconnectivity experiment.

See https://github.com/ooni/probe-engine/issues/1157.

* progress

* more work towards landing this diff

* Apply suggestions from code review
2021-03-23 16:46:46 +01:00
Arturo Filastò
70d7c1a22c
Add signal to the im test group (#259)
* Add signal to the im test group

* fix(ipconfig_test.go): disable when running in CI

Reference issue: https://github.com/ooni/probe/issues/1418

* fix(geolocate): remove unused variable

Came across this while looking into this issue with the CI that
is now failing. Guess fixing it here comes across as leaving the
camp slightly less in a bad shape than how I found it.

Co-authored-by: Simone Basso <bassosimone@gmail.com>
2021-03-22 14:31:50 +01:00
Simone Basso
28ce79eff1
feat(ooapi): add toplevel client and simplify API (#248)
* feat(ooapi): add toplevel client and simplify API

This diff should simplify using ooapi from other packages by
adding more abstraction that wraps the existing code.

Part of https://github.com/ooni/probe/issues/1355.

* fix(ooapi): use correct comment for cloners

See https://github.com/ooni/probe-cli/pull/248#discussion_r590663843

* fix(ooapi): make sure the documentation is current

See https://github.com/ooni/probe-cli/pull/248#discussion_r590665773

* fix(ooapi): automate copying APIs

See https://github.com/ooni/probe-cli/pull/248#discussion_r590665837

* feat(ooapi): add unit tests for clientcall.go

See https://github.com/ooni/probe-cli/pull/248#discussion_r590666297

* fix(ooapi): rewrite integration tests to use toplevel API

See https://github.com/ooni/probe-cli/pull/248#discussion_r590665084
2021-03-19 09:30:42 +01:00
Simone Basso
c324822870
fix(stunreachability): avoid goroutine spin and memleak (#255)
This fix addresses the bug described in issue https://github.com/ooni/probe/issues/1403.
2021-03-15 10:59:28 +01:00
Simone Basso
a02052fb0c
chore: rename stun_reachability => stunreachability (#254)
See https://github.com/ooni/probe/issues/1394

Ok @hellais @FedericoCeratto
2021-03-11 19:35:22 +01:00
Simone Basso
fbee736e90
fix(geolocate): no proxy when discovering our IP address (#251)
* fix(geolocate): no proxy when discovering our IP address

The use case of --proxy is that you cannot contact the OONI
backend otherwise. It is wrong, though, using the proxy when
discovering our IP address. The measurement won't use the
proxy anyway. Therefore, we need to use the IP address that
is performing the measurement. Not the one of the proxy.

What's more, stun is not using a proxy. Therefore, it does
not make much sense that http IP resolvers use a proxy. This
leads to inconsistencies. So, here's anothe reason why this
patch is a good thing (TM).

Finally, because knowing the IP address enables us to sanitize
the data, it's important we discover the correct IP.

Now, up until this point, the `--proxy` option has mostly
been a developers toy. But, users have asked us to have the
possibility of configuring a proxy.

This explains why I have been looking into making `--proxy`
right for a couple of hours now.

See https://github.com/ooni/probe/issues/1382

* fix(session): properly configure the IP lookupper
2021-03-10 12:01:08 +01:00
Simone Basso
f0110fe85a
fix(sessionresolver): honour the proxy (#250)
In reality, we are not going to use the sessionresolver when we're
using a proxy (I just tested). But, it nonetheless feels a lot more
robust to write a correct sessionresolver that handles the proxy
in the most correct way. That is, the sessionresolver will now skip
all the entries that cannot use a socks5 proxy (including among them
also the system resolver). What's more, it will construct a child
resolver that propagates the proxy.

We have confidence that this holds true because we have added a test
ensuring that we are really using the configured proxy.

See https://github.com/ooni/probe/issues/1381
2021-03-10 10:39:57 +01:00
Simone Basso
2ef5fb503a
fix(webconnectivity): allow measuring https://1.1.1.1 (#241)
* fix(webconnectivity): allow measuring https://1.1.1.1

There were two issues preventing us from doing so:

1. in netx, the address resolver was too later in the resolver
chain. Therefore, its result wasn't added to the events.

2. when building the DNSCache (in httpget.go), we didn't consider
the case where the input is an address. We need to treat this
case specially to make sure there is no DNSCache.

See https://github.com/ooni/probe/issues/1376.

* fix: add unit tests for code making the dnscache

* fix(netx): make sure all tests pass

* chore: bump webconnectivity version
2021-03-08 12:05:43 +01:00
Simone Basso
55bdebe8b2
engine/ooapi: autogenerated API with login and caching (#234)
* internal/engine/ooapi: auto-generated API client

* feat: introduce the callers abstraction

* feat: implement API caching on disk

* feat: implement cloneWithToken when we require login

* feat: implement login

* fix: do not cache all APIs

* feat: start making space for more tests

* feat: implement caching policy

* feat: write tests for caching layer

* feat: add integration tests and fix some minor issues

* feat: write much more unit tests

* feat: add some more easy unit tests

* feat: add tests that use a local server

While there, make sure many fields we care about are OK.

* doc: write basic documentation

* fix: tweak sentence

* doc: improve ooapi documentation

* doc(ooapi): other documentation improvements

* fix(ooapi): remove caching for most APIs

We discussed this topic yesterday with @FedericoCeratto. The only
place where we want LRU caching is MeasurementMeta.

* feat(ooapi): improve handling of errors during login

This was also discussed yesterday with @FedericoCeratto

* fix(swaggerdiff_test.go): temporarily disable

Before I work on this, I need to tend onto other tasks.

* fix(ootest): add one more test case

We're going towards 100% coverage of this package, as it ought to be.

* feat(ooapi): test cases for when the probe clock is off

* fix(ooapi): change test to have 100% unittest coverage

* feat: sync server and client APIs definition

Companion PR: https://github.com/ooni/api/pull/218

* fix(ooapi): start testing again against API

* fix(ooapi): only generate each file once

* chore: set version to 3.7.0-alpha

While there, make sure we don't always skip a currently failing
riseupvpn test, and slightly clarify the readme.

* fix(kvstore): less scoped error message
2021-03-04 11:51:07 +01:00
Simone Basso
ae32ffa13b
chore: set version to 3.7.0-alpha (#240)
While there, make sure we don't always skip a currently failing
riseupvpn test, and slightly clarify the readme.
2021-03-04 11:36:41 +01:00
Simone Basso
0d4323ae66
Release 3.6.0 (#239)
* chore: update dependencies

* chore: update user agent for measurements

* chore: we're now at v3.6.0

* chore: update assets

* chore: update bundled CA

* fix: address some goreportcard.com warnings

* fix(debian/changelog): zap release that breaks out build scripts

We're forcing the content of changelog with `dch`, so it's fine to
not have any specific new release in there.

* fix: make sure tests are passing locally

Notably, I removed a chunk of code where we were checking for network
activity. Now we don't fetch the databases and it's not important. Before,
it was important because the databases are ~large.

* fix: temporarily comment out riseupvn integration tests

See https://github.com/ooni/probe/issues/1354 for work aimed at
reducing the rate of false positives (thanks @cyBerta!)
2021-03-03 14:42:17 +01:00
Simone Basso
034db78f94
refactor(sessionresolver): adapt to changing network conditions (#238)
* feat(sessionresolver): try many and use what works

* fix(sessionresolver): make sure we can use quic

* fix: the config struct is unnecessary

* fix: make kvstore optional

* feat: write simple integration test

* feat: start adding tests

* feat: continue writing tests

* fix(sessionresolver): add more unit tests

* fix(sessionresolver): finish adding tests

* refactor(sessionresolver): changes after code review
2021-03-03 11:28:39 +01:00
Simone Basso
322394fe63
feat: use go1.16 and resources embedding (#235)
* feat: use go1.16 embedding for resources

We want to embed everything that can be easily embedded. We should, at a
minimum, replace the downloading of resources and bindata.

Ref: https://github.com/ooni/probe/issues/1367.

* fix: get rid of bindata and use go embed instead

* fix: start unbreaking some automatic tests

* fix: fetch resources as part of the mobile build

* fix: convert more stuff to go1.16

I still expect many breakages, but we'll fix them.

* fix: make the windows CI green

* fix: get resources before running QA

* fix: go1.16 uses modules by default

* hopefully fix all other outstanding issues

* fix(QA/telegram.py): add another DC IP address

* Apply suggestions from code review
2021-03-02 12:08:24 +01:00
Arturo Filastò
f46fbcad16
Add new telegram DC endpoint (#232)
* Add new telegram DC endpoint

Based on: 65ba81f504/Telegram/SourceFiles/mtproto/mtproto_dc_options.cpp

* Update internal/engine/experiment/telegram/telegram.go

Co-authored-by: Simone Basso <bassosimone@gmail.com>
2021-02-26 14:11:24 +01:00
Arturo Filastò
5e5cfa72e7
MVP of a signal messenger test (#230)
* MVP of a signal messenger test

* Add minimal signal test unit tests

* Add Signal test to the im nettest group

* Add test for https://sfu.voip.signal.org/

* Fix bug in client-side determination of blocking status

* Add uptime.signal.org to the test targets

* Add more tests

* Check for invalid CA being passed
* Check that the update function works as expected

* Update internal/engine/experiment/signal/signal_test.go

Co-authored-by: Simone Basso <bassosimone@gmail.com>

* fix: back out URL we shouldn't have changed

When merging probe-engine into probe-cli, we changed too many URLs
and some of them should not have been changed.

I noticed this during the review of Signal and I choose to add
this commit to revert such changes.

While there, make sure the URL of the experiment is OK.

* fix(signal): reach 100% of coverage

Just so that we can focus on areas of the codebase where we need
more coverage, let us avoid missing an easy line to test.

Co-authored-by: Simone Basso <bassosimone@gmail.com>
2021-02-26 10:16:34 +01:00
Simone Basso
3155549513
fix(http body saver): properly deal with EOF terminated bodies (#226)
See https://github.com/ooni/probe-engine/issues/1191
2021-02-11 14:57:14 +01:00
Simone Basso
c41114261c
Revert "fix(riseupvpn): skip currently failing tests (#212)" (#225)
This reverts commit 43f95e2c9a.

We can now safely close https://github.com/ooni/probe/issues/1338,
since the upstream issue is gone. I think this issue we have seen is
also possibly related to https://github.com/ooni/probe/issues/1348.

Cc: @cyberta.
2021-02-11 10:10:52 +01:00
Simone Basso
18ca6d5f35
fix: use golang.org/x/sys/execabs (#224)
Closes https://github.com/ooni/probe-engine/issues/1195
2021-02-10 07:40:48 +01:00