Beispiel #1
0
 def get(self):
     ua = self.request.headers['User-Agent']
     if 'ua' in self.request.GET:
         ua = self.request.GET['ua']
     self.response.headers['Access-Control-Allow-Origin'] = '*'
     self.response.content_type = 'application/json'
     self.response.write(json.dumps(woothee.parse(ua)))
Beispiel #2
0
def main(args):
    parser = argparse.ArgumentParser()
    parser.add_argument('--sql',
                        action='store',
                        default=None,
                        help='the filename of the SQLite DB to create')
    parser.add_argument('infile',
                        nargs='?',
                        type=argparse.FileType('r'),
                        default=sys.stdin)
    parser.add_argument('outfile',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout)
    args = parser.parse_args(args)

    if args.sql:
        writer = new_sqlite_writer(args.sql)
    else:
        writer = new_csv_writer(args.outfile)

    while True:
        line = args.infile.readline().strip()
        if not line:
            break

        log_entry = json.loads(line.encode('utf-8'))

        device_type = log_entry['client']['deviceType']
        ua_string = log_entry['clientRequest']['userAgent']
        woot = woothee.parse(ua_string)
        writer.writerow([
            ua_string, woot['os'], woot['os_version'], device_type,
            woot['name'], woot['version']
        ])
Beispiel #3
0
    def test_testsets(self):
        import woothee

        check_attributes = ('name', 'category', 'os', 'version', 'vendor',
                            'os_version')

        def _can_assert(attribute, e):
            if attribute in ('name', 'category'):
                return True
            check_attributes = ('os', 'version', 'vendor', 'os_version')
            if attribute in check_attributes and attribute in e:
                return True
            return False

        for filename, groupname in TARGETS:
            with open(os.path.join(TESTSET_DIR, filename), 'rb') as fp:
                for es in yaml.load_all(fp):
                    for e in es:
                        r = woothee.parse(e['target'])
                        for attribute in check_attributes:

                            testname = groupname + (' test({0}): {1}'.format(
                                attribute, e['target']))
                            if _can_assert(attribute, e):
                                self.assertEqual(r[attribute], e[attribute],
                                                 testname)
Beispiel #4
0
    def test_testsets(self):
        import woothee

        check_attributes = ('name', 'category', 'os',
                            'version', 'vendor', 'os_version')

        def _can_assert(attribute, e):
            if attribute in ('name', 'category'):
                return True
            check_attributes = ('os', 'version', 'vendor', 'os_version')
            if attribute in check_attributes and attribute in e:
                return True
            return False

        for filename, groupname in TARGETS:
            with open(os.path.join(TESTSET_DIR, filename), 'rb') as fp:
                for es in yaml.load_all(fp):
                    for e in es:
                        r = woothee.parse(e['target'])
                        for attribute in check_attributes:

                            testname = groupname + (' test({0}): {1}'.format(
                                attribute, e['target']
                            ))
                            if _can_assert(attribute, e):
                                self.assertEqual(
                                    r[attribute],
                                    e[attribute],
                                    testname
                                )
Beispiel #5
0
def define_useragent(useragents, output='score'):
    """Define individual elements of hte useragent.

    Useragents should be a list of suspect useragents to evaluate.
    Default output will be JSON Blob containing descriptive information.
    Set output='score' to receive a threat score for each UA.

    If you're calling this from your own application, be sure 'useragents' is a list.
    If you're expecting score to be returned, leave output alone, if you want the
    features, change output to json.
    """
    response_dict = {'results': {}}
    allowlist = ('curl', 'mobileasset', 'microsoft ncsi'
                 )  # Always permit these agents
    blocklist = ('mozilla/4.0')  # Always block these user agents
    for agent in useragents:
        pua = woothee.parse(agent)
        open_count = len([x for x in list(agent) if x in ['(', '[']])
        close_count = len([x for x in list(agent) if x in [')', ']']])
        response_dict['results'].update({agent: {}})
        allow = block = False
        if agent.split(' ')[0].lower() in allowlist:
            allow = True
        elif agent.split(' ')[0].lower() in blocklist:
            block = True
        response_dict['results'][agent].update(pua)
        response_dict['results'][agent].update({'allowlisted': alllow})
        response_dict['results'][agent].update({'blocklisted': block})
        response_dict['results'][agent].update(
            {'tokens': len(agent.split(' '))})
        response_dict['results'][agent].update(
            {'ngrams': [x for x in pyngram.calc_ngram(agent, 2) if x[1] > 1]})
        if open_count != close_count:  # unbalanced
            response_dict['results'][agent].update({'unbalanced': True})
        else:
            response_dict['results'][agent].update({'unbalanced': False})
        if ';' in agent and '; ' not in agent:  # Malformed, should be '; ' between settings
            response_dict['results'][agent].update(
                {'malformed_semicolon': True})
        else:
            response_dict['results'][agent].update(
                {'malformed_semicolon': False})
        if '/' in agent and ' ' in agent and '(' not in agent:
            response_dict['results'][agent].update({'malformed_noparen': True})
        else:
            response_dict['results'][agent].update(
                {'malformed_noparen': False})
        if '==' in agent or '<' in agent or '>' in agent or '`' in agent:  # SQLi/XSS Tactics
            response_dict['results'][agent].update(
                {'malformed_hacklang': True})
        else:
            response_dict['results'][agent].update(
                {'malformed_hacklang': False})
        response_dict['results'][agent].update(
            {'length': len(agent)})  # Length is kinda interesting

    if output == 'json':
        return response_dict
    else:
        return _score(response_dict)
Beispiel #6
0
def register():
    #パラメータ取得
    agent_cd = request.form['agent_cd']
    agent_name = request.form['agent_name']

    #パラメータチェック
    if not agent_cd or not agent_name:
        flash('入力してください。')
        return redirect(url_for('login'))

    #UserAgent取得
    header = request.headers.get('User-Agent')
    ua = woothee.parse(header)
    category = ua.get('category')
    name = ua.get('name')
    version = ua.get('version')
    os_name = ua.get('os')
    vendor = ua.get('vendor')
    os_version = ua.get('os_version')

    #DB登録処理
    user_agent = UserAgent(agent_cd=agent_cd, agent_name=agent_name, category=category, name=name,
                         version=version, os_name=os_name, vendor=vendor, os_version=os_version)
    try:
        db_session.add(user_agent)
        db_session.commit()
    except Exception as e:
        db_session.rollback()
        flash('既に登録済みです。')
        return redirect(url_for('login'))
    finally:
        db_session.close()

    return render_template('register.html')
Beispiel #7
0
 def test_testsets(self):
   import woothee
   for filename, groupname in TARGETS:
     f = open(os.path.join(TESTSET_DIR, filename), 'rb')
     try:
       for es in yaml.load_all(f):
         for e in es:
           r = woothee.parse(e['target'])
           for attribute in ('name', 'category', 'os', 'version', 'vendor'):
             testname = groupname + (' test(%s): %s' % (attribute, e['target']))
             if attribute in ('name', 'category') or \
               (attribute in ('os', 'version', 'vendor') and \
                 attribute in e):
               #print r[attribute], e[attribute]
               self.assertEqual(r[attribute], e[attribute], testname)
     finally:
       f.close()
Beispiel #8
0
 def test_testsets(self):
   import woothee
   for filename, groupname in TARGETS:
     f = open(os.path.join(TESTSET_DIR, filename), 'rb')
     try:
       for es in yaml.load_all(f):
         for e in es:
           r = woothee.parse(e['target'])
           for attribute in ('name', 'category', 'os', 'version', 'vendor'):
             testname = groupname + (' test(%s): %s' % (attribute, e['target']))
             if attribute in ('name', 'category') or \
               (attribute in ('os', 'version', 'vendor') and \
                 attribute in e):
               #print r[attribute], e[attribute]
               self.assertEqual(r[attribute], e[attribute], testname)
     finally:
       f.close()
def extract_features_from_log(line, source):

    if source == 'training_data':
        assert len(line) == 4
        status=(get_status( line[3].split('\n')[0]))

    elif source == 'live_data':
        assert len(line) == 3

    # Parse IP
    ip=(line[0])
    j = ip.split('.')
    ip_1 = int(j[0])
    ip_2 = int(j[1])
    ip_3 = int(j[2])
    ip_4 = int(j[3])

    # Parse User Agent
    user_agent=( urllib.unquote(line[1]) )

    p = woothee.parse(user_agent.replace('+',' '))
    category = get_category ( p['category'].lower())
    os_version = get_os_version( p['os_version'].lower() )
    vendor = get_vendor( p['vendor'].lower())
    name = get_name( p['name'].lower())
    os = get_os_family( p['os'].lower())
    version = get_version(p['version'].lower())

    # Parse Referer
    referer=( urllib.unquote(line[2]) )
    p = urlparse(referer)
    scheme= get_scheme( p.scheme)
    hostname = get_hostname( p.hostname)
    alexa_top_million = get_alexa_top_million(p.hostname)
    len_path = len( p.path)
    len_query = len(p.query)
    len_host = str(p.hostname).count('.')

    if source == 'training_data':
        return [ip_1, ip_2, ip_3, ip_4, category, os_version, version, vendor, name, os,
                        scheme, hostname, alexa_top_million, len_path, len_query, len_host, status]
    elif source == 'live_data':
        return [ip_1, ip_2, ip_3, ip_4, category, os_version, version, vendor, name, os,
                    scheme, hostname, alexa_top_million, len_path, len_query, len_host]
Beispiel #10
0
def modify_row_td(request):
    ua = request.headers.get(u"User-Agent")
    ua_parse = woothee.parse(ua)
    headers = request.headers
    modified = str(request.params.get(u"modified"))
    row = json.loads(base64.b64decode(request.params.get(u"data")))
    for i in [u"td_path", u"td_referrer", u"td_url"]:
        if (row.get(i)):
            row[i] = urllib2.unquote(row[i].encode('utf8'))
    row.update({
        u"time": float(".".join([modified[0:10], modified[10:13]])),
        u"bqid": generate_bqid(request.cookies),
        u"td_ip": request.remote_addr,
        u"td_browser": ua_parse.get(u"name"),
        u"td_browser_version": ua_parse.get(u"version"),
        u"td_os": ua_parse.get(u"os"),
        u"td_os_version": ua_parse.get(u"os_version"),
        u"user_agent": ua,
        u"x_country": headers.get(u"X-Appengine-Country"),
        u"x_region": headers.get(u"X-Appengine-Region"),
        u"x_city": headers.get(u"X-Appengine-City"),
        u"x_citylatlong": headers.get(u"X-Appengine-Citylatlong"),
    })
    return row
Beispiel #11
0
def modify_row_beacon(request):
    ua = request.headers.get(u"User-Agent")
    ua_parse = woothee.parse(ua)
    headers = request.headers
    params = request.params
    row = {}
    for key in params.keys():
        row[key] = params[key]
    row.update({
        u"time": time.time(),
        u"bqid": generate_bqid(request.cookies),
        u"referrer": headers.get(u"Referer"),
        u"td_ip": request.remote_addr,
        u"td_browser": ua_parse.get(u"name"),
        u"td_browser_version": ua_parse.get(u"version"),
        u"td_os": ua_parse.get(u"os"),
        u"td_os_version": ua_parse.get(u"os_version"),
        u"user_agent": ua,
        u"x_country": headers.get(u"X-Appengine-Country"),
        u"x_region": headers.get(u"X-Appengine-Region"),
        u"x_city": headers.get(u"X-Appengine-City"),
        u"x_citylatlong": headers.get(u"X-Appengine-Citylatlong"),
    })
    return row
Beispiel #12
0
def modify_row_td(request):
    ua = request.headers.get(u"User-Agent")
    ua_parse = woothee.parse(ua)
    headers = request.headers
    modified = str(request.params.get(u"modified"))
    row = json.loads(base64.b64decode(request.params.get(u"data")))
    for i in [u"td_path", u"td_referrer", u"td_url"]:
        if ( row.get(i) ):
            row[i] = urllib2.unquote(row[i].encode('utf8'))
    row.update({
        u"time":                float(".".join([modified[0:10], modified[10:13]])),
        u"bqid":                generate_bqid(request.cookies),
        u"td_ip":               request.remote_addr,
        u"td_browser":          ua_parse.get(u"name"),
        u"td_browser_version":  ua_parse.get(u"version"),
        u"td_os":               ua_parse.get(u"os"),
        u"td_os_version":       ua_parse.get(u"os_version"),
        u"user_agent":          ua,
        u"x_country":           headers.get(u"X-Appengine-Country"),
        u"x_region":            headers.get(u"X-Appengine-Region"),
        u"x_city":              headers.get(u"X-Appengine-City"),
        u"x_citylatlong":       headers.get(u"X-Appengine-Citylatlong"),
        })
    return row
Beispiel #13
0
def modify_row_beacon(request):
    ua = request.headers.get(u"User-Agent")
    ua_parse = woothee.parse(ua)
    headers = request.headers
    params = request.params
    row = {}
    for key in params.keys():
        row[key] = params[key]
    row.update({
        u"time":                time.time(),
        u"bqid":                generate_bqid(request.cookies),
        u"referrer":            headers.get(u"Referer"),
        u"td_ip":               request.remote_addr,
        u"td_browser":          ua_parse.get(u"name"),
        u"td_browser_version":  ua_parse.get(u"version"),
        u"td_os":               ua_parse.get(u"os"),
        u"td_os_version":       ua_parse.get(u"os_version"),
        u"user_agent":          ua,
        u"x_country":           headers.get(u"X-Appengine-Country"),
        u"x_region":            headers.get(u"X-Appengine-Region"),
        u"x_city":              headers.get(u"X-Appengine-City"),
        u"x_citylatlong":       headers.get(u"X-Appengine-Citylatlong"),
        })
    return row
Beispiel #14
0
    def test_non_provide_testsets(self):
        # This test pattern that does not exist in testsets.
        # The main purpose is that each logic to pass.
        # UserAgent is a dummy that does not exist in the world.

        import woothee

        # 48 line in lib/woothee/appliance.py
        self.assertEqual(
            {
                "name": "Nintendo DSi",
                "version": "UNKNOWN",
                "os": "Nintendo DSi",
                "os_version": "UNKNOWN",
                "category": "appliance",
                "vendor": "Nintendo",
            }, woothee.parse("(Nintendo DSi; U; ja)"))

        # 50 line in lib/woothee/appliance.py
        self.assertEqual(
            {
                "name": "Nintendo Wii",
                "version": "UNKNOWN",
                "os": "Nintendo Wii",
                "os_version": "UNKNOWN",
                "category": "appliance",
                "vendor": "Nintendo",
            }, woothee.parse("(Nintendo Wii; U; ; 3642; ja)"))

        # 26 line lib/woothee/browser.py
        self.assertEqual(
            {
                "name": "Internet Explorer",
                "version": "11.0",
                "os": "Windows Phone OS",
                "os_version": "8.1",
                "category": "smartphone",
                "vendor": "Microsoft",
            },
            woothee.parse(
                "Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0;"
                " Touch; IEMobile/11.0; NOKIA; Lumia 930) like Gecko"))

        # 159 line lib/woothee/crawler.py
        self.assertEqual(
            {
                "name": "UNKNOWN",
                "version": "UNKNOWN",
                "os": "UNKNOWN",
                "os_version": "UNKNOWN",
                "category": "UNKNOWN",
                "vendor": "UNKNOWN",
            }, woothee.parse("Data-Hotel-Cat/1.1"))

        # 74-75 line lib/woothee/mobilephone.py
        self.assertEqual(
            {
                "name": "SymbianOS",
                "version": "UNKNOWN",
                "os": "SymbianOS",
                "os_version": "UNKNOWN",
                "category": "mobilephone",
                "vendor": "UNKNOWN",
            }, woothee.parse("SymbianOS/9.2;"))

        # 78-80 line lib/woothee/mobilephone.py
        self.assertEqual(
            {
                "name": "Mobile Transcoder",
                "version": "Hatena",
                "os": "Mobile Transcoder",
                "os_version": "UNKNOWN",
                "category": "mobilephone",
                "vendor": "UNKNOWN",
            },
            woothee.parse("(compatible; Hatena-Mobile-Gateway/1.2;"
                          " +http://mgw.hatena.ne.jp/help)"))

        # 25-27 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "UNKNOWN",
                "version": "UNKNOWN",
                "os": "Windows UNKNOWN Ver",
                "os_version": "UNKNOWN",
                "category": "pc",
                "vendor": "UNKNOWN",
            },
            woothee.parse(
                "Mozilla/5.0 (Windows ; rv:8.0) Gecko/20111105 Thunderbird/8.0"
            ))

        # 49 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "Internet Explorer",
                "version": "UNKNOWN",
                "os": "Windows NT 4.0",
                "os_version": "NT 4.0",
                "category": "pc",
                "vendor": "Microsoft",
            },
            woothee.parse(
                "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0)"))

        # 51 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "Internet Explorer",
                "version": "6.0",
                "os": "Windows 98",
                "os_version": "98",
                "category": "pc",
                "vendor": "Microsoft",
            }, woothee.parse("Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"))

        # 53 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "Internet Explorer",
                "version": "5.50",
                "os": "Windows 95",
                "os_version": "95",
                "category": "pc",
                "vendor": "Microsoft",
            },
            woothee.parse(
                "Mozilla/4.0 (compatible; MSIE 5.50; Windows 95; SiteKiosk 4.8)"
            ))

        # 121 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "UNKNOWN",
                "version": "UNKNOWN",
                "os": "iPad",
                "os_version": "UNKNOWN",
                "category": "smartphone",
                "vendor": "UNKNOWN",
            }, woothee.parse("Mozilla/5.0 (iPad; "))

        # 123 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "UNKNOWN",
                "version": "UNKNOWN",
                "os": "iPod",
                "os_version": "UNKNOWN",
                "category": "smartphone",
                "vendor": "UNKNOWN",
            }, woothee.parse("Mozilla/5.0 (iPod; "))

        # 183-185 line lib/woothee/os.py
        self.assertEqual(
            {
                "name": "Mobile Transcoder",
                "version": "Naver",
                "os": "Mobile Transcoder",
                "os_version": "UNKNOWN",
                "category": "mobilephone",
                "vendor": "UNKNOWN",
            }, woothee.parse("Naver Transcoder"))
Beispiel #15
0
 def is_smartphone(ua):
     category = woothee.parse(ua)['category']
     return category.endswith('phone')
def output(queue, keu2):
    for line in iter(queue.get, sentinel):
        if line:
            if (line.HTTP_USER_AGENT and len(line.HTTP_USER_AGENT) > 5
                    and "decode" not in line.HTTP_USER_AGENT):
                try:
                    user_agent = woothee.parse(line.HTTP_USER_AGENT)
                    line.ua_os = user_agent['os']
                    line.ua_name = user_agent['name']
                    line.ua_category = user_agent['category']
                except:
                    line.ua_os = ""
                    line.ua_name = ""
                    line.ua_category = ""
            else:
                line.ua_os = ""
                line.ua_name = ""
                line.ua_category = ""

            if (len(line.REMOTE_ADDR) < 16 and len(line.REMOTE_ADDR) > 3):
                try:
                    line.victime_country = countrydb.country_name_by_addr(
                        line.REMOTE_ADDR)
                except:
                    line.victime_country = "unknown"

                if not line.victime_country:
                    line.victime_country = "unknown"

                try:
                    city = citydb.record_by_addr(line.REMOTE_ADDR)

                except:
                    line.victime_city = "unknown"
                try:
                    line.asn_victime = asndb.org_by_name(line.REMOTE_ADDR)
                except:
                    line.asn_victime = "unknown"

                if not line.asn_victime:
                    line.asn_victime = "unknown"
            else:
                line.victime_country = "unknown"
                line.asn_victime = "unknown"

            if city and "unknown" not in city:
                line.victime_city = city['city']
                if not line.victime_city:
                    line.victime_city = "unknown"
            else:
                line.victime_city = "unknown"

            try:
                line.website_tld = get_tld(line.HTTP_HOST,
                                           fix_protocol=True,
                                           as_object=True).suffix
            except:
                line.website_tld = line.HTTP_HOST

            keu2.put(line)

    keu2.put(sentinel2)
Beispiel #17
0
    def test_non_provide_testsets(self):
        # This test pattern that does not exist in testsets.
        # The main purpose is that each logic to pass.
        # UserAgent is a dummy that does not exist in the world.

        import woothee

        # 48 line in lib/woothee/appliance.py
        self.assertEqual({
            "name": "Nintendo DSi",
            "version": "UNKNOWN",
            "os": "Nintendo DSi",
            "os_version": "UNKNOWN",
            "category": "appliance",
            "vendor": "Nintendo",
        }, woothee.parse("(Nintendo DSi; U; ja)"))

        # 50 line in lib/woothee/appliance.py
        self.assertEqual({
            "name": "Nintendo Wii",
            "version": "UNKNOWN",
            "os": "Nintendo Wii",
            "os_version": "UNKNOWN",
            "category": "appliance",
            "vendor": "Nintendo",
        }, woothee.parse("(Nintendo Wii; U; ; 3642; ja)"))

        # 26 line lib/woothee/browser.py
        self.assertEqual({
            "name": "Internet Explorer",
            "version": "11.0",
            "os": "Windows Phone OS",
            "os_version": "8.1",
            "category": "smartphone",
            "vendor": "Microsoft",
        }, woothee.parse(
            "Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0;"
            " Touch; IEMobile/11.0; NOKIA; Lumia 930) like Gecko"
        ))

        # 159 line lib/woothee/crawler.py
        self.assertEqual({
            "name": "UNKNOWN",
            "version": "UNKNOWN",
            "os": "UNKNOWN",
            "os_version": "UNKNOWN",
            "category": "UNKNOWN",
            "vendor": "UNKNOWN",
        }, woothee.parse("Data-Hotel-Cat/1.1"))

        # 74-75 line lib/woothee/mobilephone.py
        self.assertEqual({
            "name": "SymbianOS",
            "version": "UNKNOWN",
            "os": "SymbianOS",
            "os_version": "UNKNOWN",
            "category": "mobilephone",
            "vendor": "UNKNOWN",
        }, woothee.parse("SymbianOS/9.2;"))

        # 78-80 line lib/woothee/mobilephone.py
        self.assertEqual({
            "name": "Mobile Transcoder",
            "version": "Hatena",
            "os": "Mobile Transcoder",
            "os_version": "UNKNOWN",
            "category": "mobilephone",
            "vendor": "UNKNOWN",
        }, woothee.parse(
            "(compatible; Hatena-Mobile-Gateway/1.2;"
            " +http://mgw.hatena.ne.jp/help)"
        ))

        # 25-27 line lib/woothee/os.py
        self.assertEqual({
            "name": "UNKNOWN",
            "version": "UNKNOWN",
            "os": "Windows UNKNOWN Ver",
            "os_version": "UNKNOWN",
            "category": "pc",
            "vendor": "UNKNOWN",
        }, woothee.parse(
            "Mozilla/5.0 (Windows ; rv:8.0) Gecko/20111105 Thunderbird/8.0"
        ))

        # 49 line lib/woothee/os.py
        self.assertEqual({
            "name": "Internet Explorer",
            "version": "UNKNOWN",
            "os": "Windows NT 4.0",
            "os_version": "NT 4.0",
            "category": "pc",
            "vendor": "Microsoft",
        }, woothee.parse(
            "Mozilla/4.0 (compatible; MSIE 6.0b; Windows NT 4.0)"
        ))

        # 51 line lib/woothee/os.py
        self.assertEqual({
            "name": "Internet Explorer",
            "version": "6.0",
            "os": "Windows 98",
            "os_version": "98",
            "category": "pc",
            "vendor": "Microsoft",
        }, woothee.parse(
            "Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)"
        ))

        # 53 line lib/woothee/os.py
        self.assertEqual({
            "name": "Internet Explorer",
            "version": "5.50",
            "os": "Windows 95",
            "os_version": "95",
            "category": "pc",
            "vendor": "Microsoft",
        }, woothee.parse(
            "Mozilla/4.0 (compatible; MSIE 5.50; Windows 95; SiteKiosk 4.8)"
        ))

        # 121 line lib/woothee/os.py
        self.assertEqual({
            "name": "UNKNOWN",
            "version": "UNKNOWN",
            "os": "iPad",
            "os_version": "UNKNOWN",
            "category": "smartphone",
            "vendor": "UNKNOWN",
        }, woothee.parse("Mozilla/5.0 (iPad; "))

        # 123 line lib/woothee/os.py
        self.assertEqual({
            "name": "UNKNOWN",
            "version": "UNKNOWN",
            "os": "iPod",
            "os_version": "UNKNOWN",
            "category": "smartphone",
            "vendor": "UNKNOWN",
        }, woothee.parse("Mozilla/5.0 (iPod; "))

        # 183-185 line lib/woothee/os.py
        self.assertEqual({
            "name": "Mobile Transcoder",
            "version": "Naver",
            "os": "Mobile Transcoder",
            "os_version": "UNKNOWN",
            "category": "mobilephone",
            "vendor": "UNKNOWN",
        }, woothee.parse("Naver Transcoder"))
Beispiel #18
0
def is_smartphone(ua):
    category = woothee.parse(ua)['category']
    return category.endswith('phone')