1import netrc, os, unittest, sys, textwrap 2from test.support import os_helper, run_unittest 3 4try: 5 import pwd 6except ImportError: 7 pwd = None 8 9temp_filename = os_helper.TESTFN 10 11class NetrcTestCase(unittest.TestCase): 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 311def test_main(): 312 run_unittest(NetrcTestCase) 313 314if __name__ == "__main__": 315 test_main() 316