1import netrc, os, unittest, sys, tempfile, textwrap
2from test import support
3
4
5class NetrcTestCase(unittest.TestCase):
6
7    def make_nrc(self, test_data):
8        test_data = textwrap.dedent(test_data)
9        mode = 'w'
10        if sys.platform != 'cygwin':
11            mode += 't'
12        temp_fd, temp_filename = tempfile.mkstemp()
13        with os.fdopen(temp_fd, mode=mode) as fp:
14            fp.write(test_data)
15        self.addCleanup(os.unlink, temp_filename)
16        return netrc.netrc(temp_filename)
17
18    def test_default(self):
19        nrc = self.make_nrc("""\
20            machine host1.domain.com login log1 password pass1 account acct1
21            default login log2 password pass2
22            """)
23        self.assertEqual(nrc.hosts['host1.domain.com'],
24                         ('log1', 'acct1', 'pass1'))
25        self.assertEqual(nrc.hosts['default'], ('log2', None, 'pass2'))
26
27        nrc2 = self.make_nrc(nrc.__repr__())
28        self.assertEqual(nrc.hosts, nrc2.hosts)
29
30    def test_macros(self):
31        nrc = self.make_nrc("""\
32            macdef macro1
33            line1
34            line2
35
36            macdef macro2
37            line3
38            line4
39            """)
40        self.assertEqual(nrc.macros, {'macro1': ['line1\n', 'line2\n'],
41                                      'macro2': ['line3\n', 'line4\n']})
42
43    def _test_passwords(self, nrc, passwd):
44        nrc = self.make_nrc(nrc)
45        self.assertEqual(nrc.hosts['host.domain.com'], ('log', 'acct', passwd))
46
47    def test_password_with_leading_hash(self):
48        self._test_passwords("""\
49            machine host.domain.com login log password #pass account acct
50            """, '#pass')
51
52    def test_password_with_trailing_hash(self):
53        self._test_passwords("""\
54            machine host.domain.com login log password pass# account acct
55            """, 'pass#')
56
57    def test_password_with_internal_hash(self):
58        self._test_passwords("""\
59            machine host.domain.com login log password pa#ss account acct
60            """, 'pa#ss')
61
62    def _test_comment(self, nrc, passwd='pass'):
63        nrc = self.make_nrc(nrc)
64        self.assertEqual(nrc.hosts['foo.domain.com'], ('bar', None, passwd))
65        self.assertEqual(nrc.hosts['bar.domain.com'], ('foo', None, 'pass'))
66
67    def test_comment_before_machine_line(self):
68        self._test_comment("""\
69            # comment
70            machine foo.domain.com login bar password pass
71            machine bar.domain.com login foo password pass
72            """)
73
74    def test_comment_before_machine_line_no_space(self):
75        self._test_comment("""\
76            #comment
77            machine foo.domain.com login bar password pass
78            machine bar.domain.com login foo password pass
79            """)
80
81    def test_comment_before_machine_line_hash_only(self):
82        self._test_comment("""\
83            #
84            machine foo.domain.com login bar password pass
85            machine bar.domain.com login foo password pass
86            """)
87
88    def test_comment_at_end_of_machine_line(self):
89        self._test_comment("""\
90            machine foo.domain.com login bar password pass # comment
91            machine bar.domain.com login foo password pass
92            """)
93
94    def test_comment_at_end_of_machine_line_no_space(self):
95        self._test_comment("""\
96            machine foo.domain.com login bar password pass #comment
97            machine bar.domain.com login foo password pass
98            """)
99
100    def test_comment_at_end_of_machine_line_pass_has_hash(self):
101        self._test_comment("""\
102            machine foo.domain.com login bar password #pass #comment
103            machine bar.domain.com login foo password pass
104            """, '#pass')
105
106
107    @unittest.skipUnless(os.name == 'posix', 'POSIX only test')
108    def test_security(self):
109        # This test is incomplete since we are normally not run as root and
110        # therefore can't test the file ownership being wrong.
111        d = support.TESTFN
112        os.mkdir(d)
113        self.addCleanup(support.rmtree, d)
114        fn = os.path.join(d, '.netrc')
115        with open(fn, 'wt') as f:
116            f.write("""\
117                machine foo.domain.com login bar password pass
118                default login foo password pass
119                """)
120        with support.EnvironmentVarGuard() as environ:
121            environ.set('HOME', d)
122            os.chmod(fn, 0o600)
123            nrc = netrc.netrc()
124            self.assertEqual(nrc.hosts['foo.domain.com'],
125                             ('bar', None, 'pass'))
126            os.chmod(fn, 0o622)
127            self.assertRaises(netrc.NetrcParseError, netrc.netrc)
128
129    def test_file_not_found_in_home(self):
130        d = support.TESTFN
131        os.mkdir(d)
132        self.addCleanup(support.rmtree, d)
133        with support.EnvironmentVarGuard() as environ:
134            environ.set('HOME', d)
135            self.assertRaises(FileNotFoundError, netrc.netrc)
136
137    def test_file_not_found_explicit(self):
138        self.assertRaises(FileNotFoundError, netrc.netrc,
139                          file='unlikely_netrc')
140
141    def test_home_not_set(self):
142        fake_home = support.TESTFN
143        os.mkdir(fake_home)
144        self.addCleanup(support.rmtree, fake_home)
145        fake_netrc_path = os.path.join(fake_home, '.netrc')
146        with open(fake_netrc_path, 'w') as f:
147            f.write('machine foo.domain.com login bar password pass')
148        os.chmod(fake_netrc_path, 0o600)
149
150        orig_expanduser = os.path.expanduser
151        called = []
152
153        def fake_expanduser(s):
154            called.append(s)
155            with support.EnvironmentVarGuard() as environ:
156                environ.set('HOME', fake_home)
157                environ.set('USERPROFILE', fake_home)
158                result = orig_expanduser(s)
159                return result
160
161        with support.swap_attr(os.path, 'expanduser', fake_expanduser):
162            nrc = netrc.netrc()
163            login, account, password = nrc.authenticators('foo.domain.com')
164            self.assertEqual(login, 'bar')
165
166        self.assertTrue(called)
167
168
169if __name__ == "__main__":
170    unittest.main()
171