File: auth_netrc.py

package info (click to toggle)
ddupdate 0.7.2-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 420 kB
  • sloc: python: 1,899; sh: 38; makefile: 35
file content (76 lines) | stat: -rw-r--r-- 2,615 bytes parent folder | download
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
"""
Implement credentials lookup using the ~/.netrc(5) file.
"""
import base64
import binascii
from netrc import netrc
import os.path

from ddupdate.ddplugin import AuthPlugin, AuthError


class AuthNetrc(AuthPlugin):
    """Get credentials stored in the .netrc(5) file.

    This is the original storage used before 0.7.2. It is less secure
    than for example the keyring but is convenient and, since it does
    not require anything to be unlocked, a good candidate for servers.
    """

    _name = 'netrc'
    _oneliner = 'Store credentials in .netrc(5)'
    __version__ = '0.7.2'

    def get_auth(self, machine):
        """Implement AuthPlugin::get_auth()."""
        path = os.environ.get('NETRC', '')
        if path:
            pass
        elif os.path.exists(os.path.expanduser('~/.netrc')):
            path = os.path.expanduser('~/.netrc')
        elif os.path.exists('/etc/netrc'):
            path = '/etc/netrc'
        else:
            raise AuthError("Cannot locate the netrc file (see manpage).")
        auth = netrc(path).authenticators(machine)
        if not auth:
            raise AuthError("No .netrc data found for " + machine)
        if not auth[2]:
            raise AuthError("No password found for " + machine)
        try:
            pw = base64.b64decode(auth[2]).decode('ascii')
        except (binascii.Error, UnicodeDecodeError):
            pw = auth[2]
        return auth[0], pw

    def set_password(self, machine, username, password):
        """Implement AuthPlugin::set_password()."""

        def is_matching_entry(line):
            """Return True if line contains 'machine' machine'."""
            words = line.split(' ')
            for i in range(0, len(words) - 1):
                if words[i] == 'machine' \
                        and words[i + 1].lower() == machine.lower():
                    return True
            return False

        def new_entry():
            """Return new entry."""
            pw = base64.b64encode(password.encode('utf-8')).decode('ascii')
            line = 'machine ' + machine.lower()
            if username:
                line += ' login ' + username
            line += ' password ' + pw
            return line

        path = os.path.expanduser('~/.netrc')
        lines = []
        if os.path.exists(path):
            with open(path, 'r') as f:
                lines = f.readlines()
        lines = [line for line in lines if not is_matching_entry(line)]
        lines.append(new_entry())
        lines = [line.strip() + "\n" for line in lines]
        with open(path, 'w') as f:
            f.writelines(lines)