1 import netrc, os, unittest, sys, textwrap
2 from test.support import os_helper
3
4 try:
5 import pwd
6 except ImportError:
7 pwd = None
8
9 temp_filename = os_helper.TESTFN
10
11 class ESC[4;38;5;81mNetrcTestCase(ESC[4;38;5;149munittestESC[4;38;5;149m.ESC[4;38;5;149mTestCase):
12
13 def make_nrc(self, test_data):
14 test_data = textwrap.dedent(test_data)
15 mode = 'w'
16 if sys.platform != 'cygwin':
17 mode += 't'
18 with open(temp_filename, mode, encoding="utf-8") as fp:
19 fp.write(test_data)
20 try:
21 nrc = netrc.netrc(temp_filename)
22 finally:
23 os.unlink(temp_filename)
24 return nrc
25
26 def test_toplevel_non_ordered_tokens(self):
27 nrc = self.make_nrc("""\
28 machine host.domain.com password pass1 login log1 account acct1
29 default login log2 password pass2 account acct2
30 """)
31 self.assertEqual(nrc.hosts['host.domain.com'], ('log1', 'acct1', 'pass1'))
32 self.assertEqual(nrc.hosts['default'], ('log2', 'acct2', 'pass2'))
33
34 def test_toplevel_tokens(self):
35 nrc = self.make_nrc("""\
36 machine host.domain.com login log1 password pass1 account acct1
37 default login log2 password pass2 account acct2
38 """)
39 self.assertEqual(nrc.hosts['host.domain.com'], ('log1', 'acct1', 'pass1'))
40 self.assertEqual(nrc.hosts['default'], ('log2', 'acct2', 'pass2'))
41
42 def test_macros(self):
43 data = """\
44 macdef macro1
45 line1
46 line2
47
48 macdef macro2
49 line3
50 line4
51
52 """
53 nrc = self.make_nrc(data)
54 self.assertEqual(nrc.macros, {'macro1': ['line1\n', 'line2\n'],
55 'macro2': ['line3\n', 'line4\n']})
56 # strip the last \n
57 self.assertRaises(netrc.NetrcParseError, self.make_nrc,
58 data.rstrip(' ')[:-1])
59
60 def test_optional_tokens(self):
61 data = (
62 "machine host.domain.com",
63 "machine host.domain.com login",
64 "machine host.domain.com account",
65 "machine host.domain.com password",
66 "machine host.domain.com login \"\" account",
67 "machine host.domain.com login \"\" password",
68 "machine host.domain.com account \"\" password"
69 )
70 for item in data:
71 nrc = self.make_nrc(item)
72 self.assertEqual(nrc.hosts['host.domain.com'], ('', '', ''))
73 data = (
74 "default",
75 "default login",
76 "default account",
77 "default password",
78 "default login \"\" account",
79 "default login \"\" password",
80 "default account \"\" password"
81 )
82 for item in data:
83 nrc = self.make_nrc(item)
84 self.assertEqual(nrc.hosts['default'], ('', '', ''))
85
86 def test_invalid_tokens(self):
87 data = (
88 "invalid host.domain.com",
89 "machine host.domain.com invalid",
90 "machine host.domain.com login log password pass account acct invalid",
91 "default host.domain.com invalid",
92 "default host.domain.com login log password pass account acct invalid"
93 )
94 for item in data:
95 self.assertRaises(netrc.NetrcParseError, self.make_nrc, item)
96
97 def _test_token_x(self, nrc, token, value):
98 nrc = self.make_nrc(nrc)
99 if token == 'login':
100 self.assertEqual(nrc.hosts['host.domain.com'], (value, 'acct', 'pass'))
101 elif token == 'account':
102 self.assertEqual(nrc.hosts['host.domain.com'], ('log', value, 'pass'))
103 elif token == 'password':
104 self.assertEqual(nrc.hosts['host.domain.com'], ('log', 'acct', value))
105
106 def test_token_value_quotes(self):
107 self._test_token_x("""\
108 machine host.domain.com login "log" password pass account acct
109 """, 'login', 'log')
110 self._test_token_x("""\
111 machine host.domain.com login log password pass account "acct"
112 """, 'account', 'acct')
113 self._test_token_x("""\
114 machine host.domain.com login log password "pass" account acct
115 """, 'password', 'pass')
116
117 def test_token_value_escape(self):
118 self._test_token_x("""\
119 machine host.domain.com login \\"log password pass account acct
120 """, 'login', '"log')
121 self._test_token_x("""\
122 machine host.domain.com login "\\"log" password pass account acct
123 """, 'login', '"log')
124 self._test_token_x("""\
125 machine host.domain.com login log password pass account \\"acct
126 """, 'account', '"acct')
127 self._test_token_x("""\
128 machine host.domain.com login log password pass account "\\"acct"
129 """, 'account', '"acct')
130 self._test_token_x("""\
131 machine host.domain.com login log password \\"pass account acct
132 """, 'password', '"pass')
133 self._test_token_x("""\
134 machine host.domain.com login log password "\\"pass" account acct
135 """, 'password', '"pass')
136
137 def test_token_value_whitespace(self):
138 self._test_token_x("""\
139 machine host.domain.com login "lo g" password pass account acct
140 """, 'login', 'lo g')
141 self._test_token_x("""\
142 machine host.domain.com login log password "pas s" account acct
143 """, 'password', 'pas s')
144 self._test_token_x("""\
145 machine host.domain.com login log password pass account "acc t"
146 """, 'account', 'acc t')
147
148 def test_token_value_non_ascii(self):
149 self._test_token_x("""\
150 machine host.domain.com login \xa1\xa2 password pass account acct
151 """, 'login', '\xa1\xa2')
152 self._test_token_x("""\
153 machine host.domain.com login log password pass account \xa1\xa2
154 """, 'account', '\xa1\xa2')
155 self._test_token_x("""\
156 machine host.domain.com login log password \xa1\xa2 account acct
157 """, 'password', '\xa1\xa2')
158
159 def test_token_value_leading_hash(self):
160 self._test_token_x("""\
161 machine host.domain.com login #log password pass account acct
162 """, 'login', '#log')
163 self._test_token_x("""\
164 machine host.domain.com login log password pass account #acct
165 """, 'account', '#acct')
166 self._test_token_x("""\
167 machine host.domain.com login log password #pass account acct
168 """, 'password', '#pass')
169
170 def test_token_value_trailing_hash(self):
171 self._test_token_x("""\
172 machine host.domain.com login log# password pass account acct
173 """, 'login', 'log#')
174 self._test_token_x("""\
175 machine host.domain.com login log password pass account acct#
176 """, 'account', 'acct#')
177 self._test_token_x("""\
178 machine host.domain.com login log password pass# account acct
179 """, 'password', 'pass#')
180
181 def test_token_value_internal_hash(self):
182 self._test_token_x("""\
183 machine host.domain.com login lo#g password pass account acct
184 """, 'login', 'lo#g')
185 self._test_token_x("""\
186 machine host.domain.com login log password pass account ac#ct
187 """, 'account', 'ac#ct')
188 self._test_token_x("""\
189 machine host.domain.com login log password pa#ss account acct
190 """, 'password', 'pa#ss')
191
192 def _test_comment(self, nrc, passwd='pass'):
193 nrc = self.make_nrc(nrc)
194 self.assertEqual(nrc.hosts['foo.domain.com'], ('bar', '', passwd))
195 self.assertEqual(nrc.hosts['bar.domain.com'], ('foo', '', 'pass'))
196
197 def test_comment_before_machine_line(self):
198 self._test_comment("""\
199 # comment
200 machine foo.domain.com login bar password pass
201 machine bar.domain.com login foo password pass
202 """)
203
204 def test_comment_before_machine_line_no_space(self):
205 self._test_comment("""\
206 #comment
207 machine foo.domain.com login bar password pass
208 machine bar.domain.com login foo password pass
209 """)
210
211 def test_comment_before_machine_line_hash_only(self):
212 self._test_comment("""\
213 #
214 machine foo.domain.com login bar password pass
215 machine bar.domain.com login foo password pass
216 """)
217
218 def test_comment_after_machine_line(self):
219 self._test_comment("""\
220 machine foo.domain.com login bar password pass
221 # comment
222 machine bar.domain.com login foo password pass
223 """)
224 self._test_comment("""\
225 machine foo.domain.com login bar password pass
226 machine bar.domain.com login foo password pass
227 # comment
228 """)
229
230 def test_comment_after_machine_line_no_space(self):
231 self._test_comment("""\
232 machine foo.domain.com login bar password pass
233 #comment
234 machine bar.domain.com login foo password pass
235 """)
236 self._test_comment("""\
237 machine foo.domain.com login bar password pass
238 machine bar.domain.com login foo password pass
239 #comment
240 """)
241
242 def test_comment_after_machine_line_hash_only(self):
243 self._test_comment("""\
244 machine foo.domain.com login bar password pass
245 #
246 machine bar.domain.com login foo password pass
247 """)
248 self._test_comment("""\
249 machine foo.domain.com login bar password pass
250 machine bar.domain.com login foo password pass
251 #
252 """)
253
254 def test_comment_at_end_of_machine_line(self):
255 self._test_comment("""\
256 machine foo.domain.com login bar password pass # comment
257 machine bar.domain.com login foo password pass
258 """)
259
260 def test_comment_at_end_of_machine_line_no_space(self):
261 self._test_comment("""\
262 machine foo.domain.com login bar password pass #comment
263 machine bar.domain.com login foo password pass
264 """)
265
266 def test_comment_at_end_of_machine_line_pass_has_hash(self):
267 self._test_comment("""\
268 machine foo.domain.com login bar password #pass #comment
269 machine bar.domain.com login foo password pass
270 """, '#pass')
271
272
273 @unittest.skipUnless(os.name == 'posix', 'POSIX only test')
274 @unittest.skipIf(pwd is None, 'security check requires pwd module')
275 @os_helper.skip_unless_working_chmod
276 def test_security(self):
277 # This test is incomplete since we are normally not run as root and
278 # therefore can't test the file ownership being wrong.
279 d = os_helper.TESTFN
280 os.mkdir(d)
281 self.addCleanup(os_helper.rmtree, d)
282 fn = os.path.join(d, '.netrc')
283 with open(fn, 'wt') as f:
284 f.write("""\
285 machine foo.domain.com login bar password pass
286 default login foo password pass
287 """)
288 with os_helper.EnvironmentVarGuard() as environ:
289 environ.set('HOME', d)
290 os.chmod(fn, 0o600)
291 nrc = netrc.netrc()
292 self.assertEqual(nrc.hosts['foo.domain.com'],
293 ('bar', '', 'pass'))
294 os.chmod(fn, 0o622)
295 self.assertRaises(netrc.NetrcParseError, netrc.netrc)
296 with open(fn, 'wt') as f:
297 f.write("""\
298 machine foo.domain.com login anonymous password pass
299 default login foo password pass
300 """)
301 with os_helper.EnvironmentVarGuard() as environ:
302 environ.set('HOME', d)
303 os.chmod(fn, 0o600)
304 nrc = netrc.netrc()
305 self.assertEqual(nrc.hosts['foo.domain.com'],
306 ('anonymous', '', 'pass'))
307 os.chmod(fn, 0o622)
308 self.assertEqual(nrc.hosts['foo.domain.com'],
309 ('anonymous', '', 'pass'))
310
311
312 if __name__ == "__main__":
313 unittest.main()