0db0ffe877c71f459520e97bec1661982fa184bf
[tinc] / test / integration / cmd_join.py
1 #!/usr/bin/env python3
2
3 """Test invite/join error conditions."""
4
5 import os
6 import shutil
7
8 from testlib import check, util
9 from testlib.log import log
10 from testlib.const import RUN_ACCESS_CHECKS
11 from testlib.proc import Tinc
12 from testlib.test import Test
13
14 FAKE_INVITE = "localhost:65535/pVOZMJGm3MqTvTu0UnhMGb2cfuqygiu79MdnERnGYdga5v8C"
15
16
17 def test_invite(foo: Tinc) -> None:
18     """Test successful 'invite'."""
19
20     foo.cmd("set", "Mode", "switch")
21     foo.cmd("set", "Broadcast", "mst")
22     foo.start()
23
24     log.info("test successful invitation")
25     out, _ = foo.cmd("invite", "quux")
26     check.is_in(f"localhost:{foo.port}/", out)
27
28     for filename in os.listdir(foo.sub("invitations")):
29         content = util.read_text(foo.sub(f"invitations/{filename}"))
30         if filename == "ed25519_key.priv":
31             check.is_in("-----BEGIN ED25519 PRIVATE KEY-----", content)
32         else:
33             check.is_in("Broadcast = mst", content)
34             check.is_in("Mode = switch", content)
35             check.is_in("Address = localhost", content)
36             check.is_in("Name = quux", content)
37             check.is_in(f"NetName = {foo}", content)
38             check.is_in(f"ConnectTo = {foo}", content)
39
40
41 def test_invite_errors(foo: Tinc) -> None:
42     """Test invite error conditions."""
43
44     log.info("invite node with tincd stopped")
45     _, err = foo.cmd("invite", "foobar", code=1)
46     check.is_in("Could not open pid file", err)
47
48     log.info("start node %s", foo)
49     foo.start()
50
51     log.info("invite without arguments")
52     _, err = foo.cmd("invite", code=1)
53     check.is_in("Not enough arguments", err)
54
55     log.info("invite with too many arguments")
56     _, err = foo.cmd("invite", "foo", "bar", code=1)
57     check.is_in("Too many arguments", err)
58
59     log.info("invite with invalid name")
60     _, err = foo.cmd("invite", "!@#", code=1)
61     check.is_in("Invalid name for node", err)
62
63     log.info("invite existing node")
64     _, err = foo.cmd("invite", foo.name, code=1)
65     check.is_in("already exists", err)
66
67     if RUN_ACCESS_CHECKS:
68         log.info("bad permissions on invitations are fixed")
69         invites = foo.sub("invitations")
70         os.chmod(invites, 0)
71         out, _ = foo.cmd("invite", "foobar")
72         check.has_prefix(out, "localhost:")
73
74         log.info("invitations directory is created with bad permissions on parent")
75         shutil.rmtree(invites)
76         os.chmod(foo.work_dir, 0o500)
77         out, _ = foo.cmd("invite", "foobar")
78         check.has_prefix(out, "localhost:")
79         check.true(os.access(invites, os.W_OK))
80
81         log.info("fully block access to configuration directory")
82         work_dir = foo.sub("test_no_access")
83         os.mkdir(work_dir, mode=0)
84         _, err = foo.cmd("-c", work_dir, "invite", "foobar", code=1)
85         check.is_in("Could not open", err)
86
87
88 def test_join_errors(foo: Tinc) -> None:
89     """Test join error conditions."""
90
91     log.info("try joining with redundant arguments")
92     _, err = foo.cmd("join", "bar", "quux", code=1)
93     check.is_in("Too many arguments", err)
94
95     log.info("try joining with existing configuration")
96     _, err = foo.cmd("join", FAKE_INVITE, code=1)
97     check.is_in("already exists", err)
98
99     log.info("try running without an invite URL")
100     work_dir = foo.sub("test_no_invite")
101     join = foo.tinc("-c", work_dir, "join")
102     _, err = join.communicate(input="")
103     check.equals(1, join.returncode)
104     check.is_in("Error while reading", err)
105
106     log.info("try using an invalid invite")
107     work_dir = foo.sub("test_invalid_invite")
108     _, err = foo.cmd("-c", work_dir, "join", FAKE_INVITE, code=1)
109     check.is_in("Could not connect to", err)
110
111     if RUN_ACCESS_CHECKS:
112         log.info("bad permissions on configuration directory are fixed")
113         work_dir = foo.sub("wd_access_test")
114         os.mkdir(work_dir, mode=400)
115         _, err = foo.cmd("-c", work_dir, "join", FAKE_INVITE, code=1)
116         check.is_in("Could not connect to", err)
117         check.true(os.access(work_dir, mode=os.W_OK))
118
119
120 with Test("run invite success tests") as context:
121     test_invite(context.node(init=True))
122
123 with Test("run invite error tests") as context:
124     test_invite_errors(context.node(init=True))
125
126 with Test("run join tests") as context:
127     test_join_errors(context.node(init=True))