• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cisagov / trustymail / 5072383466

pending completion
5072383466

Pull #135

github

GitHub
Merge 5b2beb1f8 into 585c9a8f8
Pull Request #135: 134 fix psl args

0 of 22 new or added lines in 3 files covered. (0.0%)

1 existing line in 1 file now uncovered.

0 of 642 relevant lines covered (0.0%)

0.0 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/trustymail/cli.py
1
"""trustymail: A tool for scanning DNS mail records for evaluating security.
2

3
Usage:
4
  trustymail (INPUT ...) [options]
5
  trustymail (INPUT ...) [--output=OUTFILE] [--timeout=TIMEOUT] [--smtp-timeout=TIMEOUT] [--smtp-localhost=HOSTNAME] [--smtp-ports=PORTS] [--no-smtp-cache] [--mx] [--starttls] [--spf] [--dmarc] [--debug] [--json] [--dns=HOSTNAMES] [--psl-filename=FILENAME] [--psl-read-only]
6
  trustymail (-h | --help)
7

8
Options:
9
  -h --help                   Show this message.
10
  -o --output=OUTFILE         Name of output file  [default: results].
11
  -t --timeout=TIMEOUT        The DNS lookup timeout in seconds [default: 5].
12
  --smtp-timeout=TIMEOUT      The SMTP connection timeout in seconds [default: 5].
13
  --smtp-localhost=HOSTNAME   The hostname to use when connecting to SMTP
14
                              servers.  (Default is the FQDN of the host from
15
                              which trustymail is being run.)
16
  --smtp-ports=PORTS          A comma-delimited list of ports at which to look
17
                              for SMTP servers [default: 25,465,587].
18
  --no-smtp-cache             Do not cache SMTP results during the run.  This
19
                              may results in slower scans due to testing the
20
                              same mail servers multiple times.
21
  --mx                        Only check MX records.
22
  --starttls                  Only check MX records and STARTTLS support.
23
                              (Implies --mx.)
24
  --spf                       Only check SPF records.
25
  --dmarc                     Only check DMARC records.
26
  --json                      Output is in JSON format.  (Default is CSV.)
27
  --debug                     Output should include more verbose logging.
28
  --dns=HOSTNAMES             A comma-delimited list of DNS servers to query
29
                              against.  For example, if you want to use
30
                              Google's DNS then you would use the
31
                              value --dns-hostnames='8.8.8.8,8.8.4.4'.  By
32
                              default the DNS configuration of the host OS
33
                              (/etc/resolv.conf) is used.  Note that
34
                              the host's DNS configuration is not used at all
35
                              if this option is used.
36
  --psl-filename=FILENAME     The name of the file where the public suffix list
37
                              (PSL) cache will be saved.  If set to the name of
38
                              an existing file then that file will be used as
39
                              the PSL.  If not present then the PSL cache will
40
                              be saved to a file in the current directory called
41
                              public_suffix_list.dat. [default: public_suffix_list.dat]
42
  --psl-read-only             If present, then the public suffix list (PSL)
43
                              cache will be read but never overwritten.  This
44
                              is useful when running in AWS Lambda, for
45
                              instance, where the local filesystem is read-only.
46

47
Notes:
48
   If no scan type options are specified, all are run against a given domain/input.
49
"""
50
# Standard Python Libraries
51
# Built-in imports
52
import errno
×
NEW
53
import json
×
54
import logging
×
55
import os
×
56

57
# Third-Party Libraries
58
# Dependency imports
59
import docopt
×
60

61
# Local imports
62
from . import trustymail
×
63
from ._version import __version__
×
64

65

66
def main():
×
67
    """Perform a trustymail scan using the provided options."""
68
    args = docopt.docopt(__doc__, version=__version__)
×
NEW
69
    print('args as interpreted by trustymail:', args)
×
70

71
    # Write the arguments to a file for use by the trustymail library
NEW
72
    with open('env.json', 'w') as env:
×
NEW
73
        json.dump(args, env)
×
74

75
    # cisagov Libraries
76
    import trustymail.trustymail as tmail
×
77

78
    log_level = logging.WARN
×
79
    if args["--debug"]:
×
80
        log_level = logging.DEBUG
×
81
    logging.basicConfig(format="%(asctime)-15s %(message)s", level=log_level)
×
82

83
    # Allow for user to input a csv for many domain names.
84
    if args["INPUT"][0].endswith(".csv"):
×
85
        domains = tmail.domain_list_from_csv(open(args["INPUT"][0]))
×
86
    else:
87
        domains = args["INPUT"]
×
88

NEW
89
    smtp_ports = {int(port) for port in args["--smtp-ports"].split(",")}
×
90

91
    if args["--dns"] is not None:
×
92
        dns_hostnames = args["--dns"].split(",")
×
93
    else:
94
        dns_hostnames = None
×
95

96
    # --starttls implies --mx
97
    if args["--starttls"]:
×
98
        args["--mx"] = True
×
99

100
    # User might not want every scan performed.
101
    scan_types = {
×
102
        "mx": args["--mx"],
103
        "starttls": args["--starttls"],
104
        "spf": args["--spf"],
105
        "dmarc": args["--dmarc"],
106
    }
107

108
    domain_scans = []
×
109
    for domain_name in domains:
×
110
        domain_scans.append(
×
111
            tmail.scan(
112
                domain_name,
113
                int(args["--timeout"]),
114
                int(args["--smtp-timeout"]),
115
                args["--smtp-localhost"],
116
                smtp_ports,
117
                not args["--no-smtp-cache"],
118
                scan_types,
119
                dns_hostnames,
120
            )
121
        )
122

NEW
123
    output_file_name = args["--output"]
×
124

125
    # Ensure file extension is present in filename.
126
    if args["--json"] and ".json" not in output_file_name:
×
127
        output_file_name += ".json"
×
128
    elif ".csv" not in output_file_name:
×
129
        output_file_name += ".csv"
×
130

131
    if args["--json"]:
×
132
        json_out = tmail.generate_json(domain_scans)
×
133
        if args["--output"] is None:
×
134
            print(json_out)
×
135
        else:
136
            write(json_out, output_file_name)
×
137
            logging.warn("Wrote results to %s." % output_file_name)
×
138
    else:
139
        tmail.generate_csv(domain_scans, output_file_name)
×
140

141

142
def write(content, out_file):
×
143
    """Write the provided content to a file after ensuring all intermediate directories exist."""
144
    parent = os.path.dirname(out_file)
×
145
    if parent != "":
×
146
        mkdir_p(parent)
×
147

148
    f = open(out_file, "w")  # no utf-8 in python 2
×
149
    f.write(content)
×
150
    f.close()
×
151

152

153
# mkdir -p in python, from:
154
# http://stackoverflow.com/questions/600268/mkdir-p-functionality-in-python
155
def mkdir_p(path):
×
156
    """Make a directory and all intermediate directories in its path."""
157
    try:
×
158
        os.makedirs(path)
×
159
    except OSError as exc:  # Python >2.5
×
160
        if exc.errno == errno.EEXIST:
×
161
            pass
×
162
        else:
163
            raise
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc