Completed
Push — master ( 13a39b...f0c535 )
by John
02:54
created

questionnaire_initial()   B

Complexity

Conditions 6

Size

Total Lines 19

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
c 0
b 0
f 0
dl 0
loc 19
rs 8
1
#!/usr/bin/env python3
2
"""Check Android autoloader files."""
3
4
import sys  # load arguments
5
import requests  # session
6
from bbarchivist import networkutils  # lookup
7
from bbarchivist import decorators  # Ctrl+C wrapping
8
from bbarchivist import jsonutils  # json
9
from bbarchivist import utilities  # argument filters
10
from bbarchivist import scriptutils  # default parser
11
12
__author__ = "Thurask"
13
__license__ = "WTFPL v2"
14
__copyright__ = "Copyright 2015-2016 Thurask"
15
16
17
def grab_args():
18
    """
19
    Parse arguments from argparse/questionnaire.
20
21
    Invoke :func:`droidlookup.droidlookup_main` with those arguments.
22
    """
23
    if len(sys.argv) > 1:
24
        parser = scriptutils.default_parser("bb-droidlookup", "Get Android autoloaders")
25
        parser.add_argument(
26
            "branch",
27
            help="OS branch, 3 letters")
28
        parser.add_argument(
29
            "floor",
30
            help="Start of search range",
31
            default=0,
32
            nargs="?",
33
            type=int,
34
            choices=range(0, 999),
35
            metavar="floor")
36
        parser.add_argument(
37
            "-d",
38
            "--device",
39
            dest="device",
40
            help="Device to check",
41
            nargs="?",
42
            type=utilities.droidlookup_devicetype,
43
            default=None)
44
        parser.add_argument(
45
            "-c",
46
            "--ceiling",
47
            dest="ceil",
48
            help="End of search range",
49
            default=999,
50
            nargs="?",
51
            type=int,
52
            choices=range(1, 1000),
53
            metavar="ceil")
54
        parser.add_argument(
55
            "-t",
56
            "--type",
57
            help="Check SHA256/512 hashes instead",
58
            default=None,
59
            type=utilities.droidlookup_hashtype)
60
        parser.add_argument(
61
            "-s",
62
            "--single",
63
            dest="single",
64
            help="Only scan one OS build",
65
            action="store_true",
66
            default=False)
67
        args = parser.parse_args(sys.argv[1:])
68
        parser.set_defaults()
69
        if args.single:
70
            args.ceil = args.floor  # range(x, x+1) == x
71
        if args.device is None:
72
            famlist = jsonutils.load_json("droidfamilies")
73
            droidlookup_main(famlist, args.branch, args.floor, args.ceil, args.type)
74
        else:
75
            droidlookup_main(args.device, args.branch, args.floor, args.ceil, args.type)
76
    else:
77
        questionnaire()
78
79
80
def questionnaire_single():
81
    """
82
    What to ask if only one lookup is needed.
83
    """
84
    while True:
85
        scanos = input("OS (ex. AAD250): ")
86
        if len(scanos) != 6:
87
            print("OS MUST BE 3 LETTERS AND 3 NUMBERS, TRY AGAIN")
88
            continue
89
        branch = scanos[:3]
90
        if not branch.isalpha():
91
            print("OS MUST BE 3 LETTERS AND 3 NUMBERS, TRY AGAIN")
92
            continue
93
        floor = scanos[3:6]
94
        if not floor.isdigit():
95
            print("OS MUST BE 3 LETTERS AND 3 NUMBERS, TRY AGAIN")
96
            continue
97
        floor = int(floor)
98
        ceil = floor
99
        break
100
    return branch, floor, ceil
101
102
103
def questionnaire_branch():
104
    """
105
    Ask about lookup branch.
106
    """
107
    while True:
108
        branch = input("BRANCH (ex. AAD): ")
109
        if len(branch) != 3 or not branch.isalpha():
110
            print("BRANCH MUST BE 3 LETTERS, TRY AGAIN")
111
            continue
112
        else:
113
            break
114
    return branch
115
116
117
def questionnaire_initial():
118
    """
119
    Ask about lookup start.
120
    """
121
    while True:
122
        try:
123
            floor = int(input("INITIAL OS (0-998): "))
124
        except ValueError:
125
            continue
126
        else:
127
            if floor < 0:
128
                print("INITIAL < 0, TRY AGAIN")
129
                continue
130
            elif floor > 998:
131
                print("INITIAL > 998, TRY AGAIN")
132
                continue
133
            else:
134
                break
135
    return floor
136
137
138
def questionnaire_final(floor):
139
    """
140
    Ask about lookup end.
141
142
    :param floor: Starting OS version.
143
    :type floor: int
144
    """
145
    while True:
146
        try:
147
            ceil = int(input("FINAL OS (1-999): "))
148
        except ValueError:
149
            ceil = 999
150
        else:
151
            if ceil < floor:
152
                print("FINAL < INITIAL, TRY AGAIN")
153
                continue
154
            elif ceil > 999:
155
                print("FINAL > 999, TRY AGAIN")
156
                continue
157
            else:
158
                break
159
    return ceil
160
161
162
def questionnaire():
163
    """
164
    Questions to ask if no arguments given.
165
    """
166
    single = utilities.s2b(input("SINGLE OS (Y/N)?: "))
167
    if single:
168
        branch, floor, ceil = questionnaire_single()
169
    else:
170
        branch = questionnaire_branch()
171
        floor = questionnaire_initial()
172
        ceil = questionnaire_final(floor)
173
    famlist = jsonutils.load_json("droidfamilies")  # same here
174
    droidlookup_main(famlist[:2], branch, floor, ceil)
175
    decorators.enter_to_exit(True)
176
177
178
@decorators.wrap_keyboard_except
179
def droidlookup_main(device, branch, floor=0, ceil=999, method=None):
180
    """
181
    Check the existence of Android factory images, in a range.
182
183
    :param device: Device to check.
184
    :type device: str
185
186
    :param branch: OS version, 3 letters.
187
    :type branch: str
188
189
    :param floor: Starting OS version, padded to 3 numbers. Default is 0.
190
    :type floor: int
191
192
    :param ceil: Ending OS version, padded to 3 numbers. Default is 999.
193
    :type ceil: int
194
195
    :param method: None for regular OS links, "hash256/512" for SHA256 or 512 hash.
196
    :type method: str
197
    """
198
    scriptutils.slim_preamble("DROIDLOOKUP")
199
    text = "DEVICE: ALL" if isinstance(device, list) else "DEVICE: {0}".format(device.upper())
200
    print(text)
201
    sess = requests.Session()
202
    for ver in range(floor, ceil + 1):
203
        build = "{0}{1}".format(branch.upper(), str(ver).zfill(3))
204
        print("NOW SCANNING: {0}".format(build), end="\r")
205
        results = networkutils.droid_scanner(build, device, method, sess)
206
        if results is not None:
207
            for result in results:
208
                print("{0} AVAILABLE! {1}\n".format(build, result), end="\r")
209
210
211
if __name__ == "__main__":
212
    grab_args()
213