summaryrefslogtreecommitdiffstats
path: root/t/srs.t
blob: a1c8104703689a4ad0e69c349a5413caaad79452 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
use strict;
use warnings;

use Test::More tests => 39;
use Test::Exception;
use Test::MockModule;

BEGIN {
    use_ok 'Spline::Srs', qw(
        config_set
        config_get
        check_exclude
        srs_forward
        srs_reverse
    ) or BAIL_OUT;
}

# Test config
my $old_value = config_get('hash_length');
isnt($old_value, undef, 'Config value exists');
config_set('hash_length', $old_value+1);
isnt(config_get('hash_length'), $old_value, 'Config changed');

is(config_get('invalid'), undef, 'Invalid config value is undef');
config_set('invalid', 'test');
is(config_get('invalid'), undef, 'Cannot set invalid config values');

# Testing ignores
is(check_exclude('test@example.com',['example.com']), 1, 'Ignore matching domain');
is(check_exclude('test@example.de', ['example.com']), 0, 'Do not ignore non-matching domain');
is(check_exclude('test@test.example.com', ['example.com']), 0, 'Do not ignore sub-domain');
is(check_exclude('test@test.example.com', ['.example.com']), 1, 'Ignore sub-domain if requested');

# Try without config
throws_ok { srs_forward('something@example.com') } qr/configure.*secret/, 'Secret required';
config_set('secret', 'abc');
throws_ok { srs_forward('something@example.com') } qr/configure.*secret/, 'Long secret required';
config_set('secret', '12345678901234567890');
throws_ok { srs_forward('something@example.com') } qr/configure.*alias/, 'Alias required';
config_set('alias', 'something');
lives_ok { srs_forward('something@example.com') } 'Config complete';

# Testing ignores with config
config_set('alias', 'domain.invalid');
is(srs_forward('test@domain.invalid'), 'test@domain.invalid', 'Exclude alias domain by default');
isnt(srs_forward('test@example.com'), 'test@example.com', 'Not excluding something other');

config_set('excludes', ['example.com']);
is(srs_forward('test@domain.invalid'), 'test@domain.invalid', 'Exclude alias domain by default');
is(srs_forward('test@example.com'), 'test@example.com', 'Exclude is working');
isnt(srs_forward('test@test.example.com'), 'test@test.example.com', 'Excluded domain should not match subdomain');

config_set('excludes', ['.example.com']);
is(srs_forward('test@domain.invalid'), 'test@domain.invalid', 'Exclude alias domain by default');
is(srs_forward('test@test.example.com'), 'test@test.example.com', 'Exclude subdomains');
isnt(srs_forward('test@example.com'), 'test@example.com', 'Excluded subdomain should not match domain');

config_set('excludes', ['example.com', '.example.com']);
is(srs_forward('test@domain.invalid'), 'test@domain.invalid', 'Exclude alias domain by default');
is(srs_forward('test@test.example.com'), 'test@test.example.com', 'Multiple excludes');
is(srs_forward('test@example.com'), 'test@example.com', 'Multiple excludes');

# SRS Forward
config_set('secret', '12345678901234567890');
config_set('alias', 'domain.invalid');
config_set('excludes', undef);
my $result = srs_forward('alex@example.com');
isnt($result, undef, 'Not undef');
isnt($result, 'alex@example.com', 'Not rewritten');
like($result, qr/^SRS0[+=-]/, 'SRS0 Prefix');
like($result, qr/\@domain\.invalid$/, 'Rewrite to alias-Domain');

# Check SRS forward an backwards
my $address = 'alex@example.com';
my $srs_address = srs_forward($address);
isnt($srs_address, undef, 'Forward works');
isnt($srs_address, $address, 'Forward works');
is(srs_reverse($srs_address), $address, 'Reverse maps back to original');

# Some checks requires a fixed time for deterministic output
my ($old_srs_address, $broken);
{
    no warnings 'redefine';
    my $timestamp_create = \&Mail::SRS::timestamp_create;
    local *Mail::SRS::timestamp_create = sub {
        my $self = shift;
        $timestamp_create->($self, 1);
    };

    $old_srs_address = srs_forward($address);
    isnt($old_srs_address, $srs_address, 'Time should have changed');
    is($old_srs_address, 'SRS0=R0OuN1=AA=example.com=alex@domain.invalid', 'exakt match with fixed time');

    # Hash with broken chars
    $broken = srs_forward('nk@example.com');
    is($broken, 'SRS0=s/6g+P=AA=example.com=nk@domain.invalid', 'srs address is as expected');
}

# Timestamp should timeout (but old timestamps can be ignored)
throws_ok { srs_reverse($old_srs_address) } qr/Invalid timestamp/, 'Timestamp should be to old';
config_set('ignore_time', 1);
lives_ok { srs_reverse($old_srs_address) } 'Ignore old timestamp';

# libsrs_alt uses different base64 chars and should also work
lives_ok { srs_reverse($broken) } 'Reverse with special chars';
$broken = 'SRS0=s.6g_P=AA=example.com=nk@domain.invalid';
throws_ok { srs_reverse($broken) } qr/Invalid hash/, 'Reverse with legacy chars';
config_set('srsalt_fallback', 1);
is(srs_reverse($broken), 'nk@example.com', 'Reverse with legacy chars');

# vim: set et ts=4: