Exemple #1
0
def process(affected=None, per_page=60):
    print('generating html: category-index ...')
    base = mylib.path_out('category')
    parent = 'All Categories'
    arr = []
    for fname, json in mylib.enum_categories():
        cid, cname = json['meta']
        arr.append([cid, cname])
        if affected and cid not in affected:
            continue
        out_dir = mylib.path_add(base, cid)
        # full url since categories can have page 2, 3, etc.
        A = HTML.h2_path_n_rank(cname, [('/category/', parent)], 'ranking/')
        Z = HTML.p_download_json('data.json', 'category-{}.json'.format(cid))
        _, a = HTML.write_app_pages(out_dir,
                                    json['apps'],
                                    cname,
                                    per_page,
                                    pre=A,
                                    post=Z)
        # write_app_pages breaks html_ranking!! call html_ranking after this!
        print('  {} ({})'.format(cname, a))
        if a > 1:
            arr[-1][-1] += ' ({})'.format(a)  # append count
        mylib.symlink(fname, mylib.path_add(out_dir, 'data.json'))

    print('  .. {} categories'.format(len(arr)))
    write_overview_page(base, arr, parent)
    print('')
Exemple #2
0
def gen_imprint():
    HTML.write(mylib.path_out(),
               '''
<h2>Imprint / Impressum</h2>
<p>
  <strong>Lehrstuhl für Privatsphäre und Sicherheit in Informationssystemen (PSI)</strong><br>
  Otto-Friedrich Universität Bamberg<br>
  Kapuzinerstr. 16<br>
  96047 Bamberg<br>
  Germany
</p>
<p>Tel.: +49 951 863-2661</p>

<h3>Inhaltliche Verantwortlichkeit i.S.v. § 5 TMG und § 55 Abs. 2 RStV</h3>
<p>Für die Richtigkeit und Aktualität der Inhalte sind die jeweiligen Erstellerinnen und Ersteller der einzelnen Seiten verantwortlich.</p>
<p>
  Otto-Friedrich Universität Bamberg<br>
  Lehrstuhl für Privatsphäre und Sicherheit in Informationssystemen (PSI)<br>
  Prof. Dr. Dominik Herrmann<br>
  An der Weberei 5<br>
  96047 Bamberg<br>
  Deutschland<br>
  Tel.: +49 951 863-2661<br>
  E-Mail: <a href="mailto:[email protected]">[email protected]</a>
</p>

<h3>Technische Verantwortlichkeit</h3>
<p>
  <strong>Webmaster/in:</strong><br>
  Prof. Dr. Dominik Herrmann<br>
  Tel.: +49 951 863-2661<br>
  E-Mail: <a href="mailto:[email protected]">[email protected]</a>
</p>''',
               fname='imprint.html')
Exemple #3
0
def gen_redirect():
    HTML.write(mylib.path_out(),
               '''
<h2>Redirecting …</h2>
<script type="text/javascript">
  var GET={};
  window.location.search.substr(1).split("&").forEach(function(x){GET[x.split("=")[0]]=x.split("=")[1]});
  if (GET["id"]) { window.location = "/app/" + GET["id"] + "/"; }
</script>''',
               fname='redirect.html')
Exemple #4
0
def process():
    print('generating html: ranking ...')
    print('  overall ranking')
    write_ranking_all('Ranking', mylib.path_out('index', 'apps', 'ranking'))

    print('  category ranking')
    for _, json in mylib.enum_categories():
        cid, name = json['meta']
        write_ranking_category(cid, name)

    print('  custom lists')
    base_custom = mylib.path_out('lists')
    title_custom = 'Lists'
    arr = []
    for list_id, json in mylib.enum_custom_lists('list_'):
        list_name = json['name']
        try:
            desc = json['desc']
        except KeyError:
            desc = None
        arr.append((list_id, list_name, len(json['apps']), desc))
        write_ranking_custom_lists(base_custom,
                                   list_id,
                                   list_name,
                                   parent_title=title_custom)

    print('    index page')
    mylib.sort_by_name(arr, 1)
    src = html_h2_path([('/results/', 'Results')], title_custom)
    src += '''
<p class="squeeze">
  App lists compare individual applications against each other.
  These curated lists group together, at least in some aspect, similar applications.
  This could be all instant messengers, health related apps, or apps from a common developer or country.
</p>
<div class="found-in">'''
    for x in arr:
        src += HTML.h4_a_title_sub_desc(x[0], x[1], f'contains {x[2]} apps',
                                        x[3])
    HTML.write(base_custom, src + '</div>', title=title_custom)
    print('')
Exemple #5
0
def process(per_page=60):
    print('generating html: app-index ...')
    title = 'Apps (A–Z)'
    header = HTML.h2_path_n_rank(title, [('/results/', 'Results')], 'ranking/')
    p, a = HTML.write_app_pages(mylib.path_out('index', 'apps'),
                                index_app_names.get_sorted_app_names(),
                                title,
                                per_page=per_page,
                                pre=header)
    # write_app_pages breaks html_ranking!! call html_ranking after this!
    print('  {} apps'.format(a))
    print('  {} pages'.format(p))
    print('')
Exemple #6
0
def write_ranking_category(cid, category_name):
    base = mylib.path_out('category', cid, 'ranking')
    # full urls since categories can have page 2, 3, etc.
    src = html_h2_path([('/category/', 'All Categories'),
                        ('/category/{}/'.format(cid), category_name)])
    src += html_default_description()
    src += html_table()
    src += HTML.p_download_json('data.json',
                                'raw-category-{}.json'.format(cid))
    src += html_script_chunk('data.json', 12, -1)  # last update desc
    HTML.write(base, src, title='Category Ranking: ' + category_name)
    mylib.symlink(index_rank.fname_rank_list('category', cid),
                  mylib.path_add(base, 'data.json'))
Exemple #7
0
def gen_appprivacy():
    HTML.write(mylib.path_out(),
               '''
<h2>Datenschutzerklärung (App)</h2>
<p>Die appchk app verarbeitet potentiell personenbeziehbare Daten.</p>
<p class="squeeze">
  Im Nachfolgenden werden diese Daten gelistet, die von der App erhoben und verarbeitet werden.
  Dies beinhaltet die Domainnamen der angesurften Webseiten bzw. von anderen Apps kontaktierte Domains, sowie das Datum und die Uhrzeit der Anfrage.
  Sofern ein App-Recording gestartet wird, wird außerdem die aktuelle Version des iOS Betriebssystems gespeichert.
  Andere als die genannten Daten werden nicht erhoben.
  Weiterhin werden diese Daten nur erhoben, solange der (lokale) VPN-Service aktiv ist.
  Wenn dieser Service inaktiv ist, werden keine Daten erhoben.
</p>
<p class="squeeze">
  Im Gegensatz zu einem konventionellen VPN Provider, verbindet sich dieser VPN-Service <strong>nicht</strong> zu einem anderen Server.
  Alle Daten werden ausschließlich auf dem eigenen Endgerät erfassten und gespeichert.
  Das heißt, diese Daten verlassen das eigene Gerät nicht und können demnach auch nicht von uns ausgewertet werden.
</p>
<p class="squeeze">
  Diese Daten werden nur an unsere Server (appchk.de) übermittelt, sofern der Nutzer / die Nutzerin der Übermittlung explizit zustimmt.
  Nutzer:innen haben weiterhin die Möglichkeit die erfassten Daten vor dem Upload zu filtern.
  Beim Übermitteln der Daten erhält der Server einen Zeitstempel der Anfrage.
  Andere Attribute wie Browsertyp, IP-Adresse, etc. werden, wie bei der Webseite, nicht ausgewertet oder gespeichert.
</p>
<p>Bei offenen Fragen wenden Sie sich bitte an <a href="mailto:[email protected]">[email protected]</a>.</p>

<h2>Privacy Policy (App)</h2>
<p>The appchk app collects potentially personally identifiable information.</p>
<p class="squeeze">
  The following section contains a list of the collected and processed data.
  This data includes the domain names of websites the user or another app contacted, as well as the date and time of the query.
  If the user starts an app-recording, the app will also store the current iOS version.
  Other than the listed data is not collected.
  Further, this data is only collected as long as the (local) VPN-service is active.
  As soon as this service is deactivated, no more data is collected.
</p>
<p class="squeeze">
  Contrary to conventional VPN providers, this VPN-service does <strong>not</strong> connect to another server.
  All collected data is processed and stored solely on the users end-device.
  This means that this data never leaves a user’s device and can therefore not be evaluated by us.
</p>
<p class="squeeze">
  This data is transmitted to our servers (appchk.de) only in the case if the user explicitly chooses to submit the data.
  Furthermore, users have the option to filter the data prior to upload.
  If the data is submitted, the server will also receive a timestamp of the upload.
  Other attributes like browser type, IP-address, etc. are, similarly to the website, not evaluated nor stored, similar.
</p>
<p>If you have further questions write an email to <a href="mailto:[email protected]">[email protected]</a>.</p>
''',
               fname='app-privacy.html')
Exemple #8
0
def gen_help():
    many = 7
    txt = '''<h2>Help needed!</h2>
<div class="squeeze"><p>
    With the release of iOS 14 some <a href="https://www.apple.com/ios/ios-14/features/#Privacy" target="_blank">Privacy</a> features are put into the spotlight.
    One of these features is making transparent how your data is being used for tracking purposes.
    Developers are now required to self-report their privacy practices.
  </p><p>
    We have selected a random sample of applications for evaluation and want to check whether the app behaviour changes over time.
    This study consists of two stages; this is the second.
    In the first stage we recorded the app communications before iOS 14 was released.
    In the second stage we repeat the process after the launch of iOS 14.
  </p><p>
    You can help us by providing app recordings of the following applications.
    Make sure to update to the lastest appchk version (v.34) which includes a check for the iOS version.
    Get the <a href="https://testflight.apple.com/join/9jjaFeHO" target="_blank">Testflight beta</a>.
  </p>
</div>
<div id="help-links">'''

    def app(bundle_id, name, appstore_id):
        iurl = 'https://apps.apple.com/de/app/id{}'.format(appstore_id)
        aref = '<a href="{}" target="_blank">AppStore</a>'.format(iurl)
        return '{} <span class="snd">Download from {}</span>'.format(
            HTML.a_app(bid, name), aref)

    def rec(count):
        return '<span class="{}"><b>{}</b>/{}</span> recordings'.format(
            'done' if count >= many else 'notyet', count, many)

    obj = mylib.json_read(mylib.path_root('src', 'help.json'))
    for land in sorted(obj.keys()):
        txt += '\n<h3>{}:</h3>\n<table class="alternate">'.format(land)
        txt += HTML.tr(['', 'App Name', 'pre iOS 14', 'post iOS 14'], 'th')
        for i, x in enumerate(obj[land]):
            bid = x[2]
            c = [0, 0]
            for fname, json in mylib.enum_jsons(bid):
                try:
                    ios14 = int(json['ios'].split('.')[0]) >= 14
                except KeyError:
                    # assume everything submitted after release date is iOS14
                    ios14 = os.path.getmtime(fname) > 1600258000
                c[1 if ios14 else 0] += 1
            txt += HTML.tr([i + 1, app(bid, x[0], x[1]), rec(c[0]), rec(c[1])])
        txt += '</table>'
    txt += '</div>'
    HTML.write(mylib.path_out('help'), txt)
Exemple #9
0
def gen_privacy():
    HTML.write(mylib.path_out(),
               '''
<h2>Datenschutzerklärung (Webseite)</h2>
<p>Auf dieser Webseite werden keine personenbezogenen Daten erhoben.</p>
<p class="squeeze">
  Einige Daten werden jedoch technisch bedingt automatisch erfasst.
  Diese Daten werden von Ihrem Browser automatisch gesendet und beinhalten Browsertyp und -version, die Referrer-URL, Ihre IP-Adresse sowie Datum und Uhrzeit der Anfrage.
  Diese Daten werden explizit weder ausgewertet noch gespeichert.
</p>
<p>Bei offenen Fragen wenden Sie sich bitte an <a href="mailto:[email protected]">[email protected]</a>.</p>

<h2>Privacy Policy (Website)</h2>
<p>This website does not collect any personally identifiable information.</p>
<p class="squeeze">
  Some data is collected automatically by our IT systems when you visit the website.
  This technical data is sent automatically by your browser and includes the browser type and version, a referrer URL, your IP address, and date and time when you accessed the page.
  This data is explicitly neither evaluated nor stored.
</p>
<p>If you have further questions write an email to <a href="mailto:[email protected]">[email protected]</a>.</p>
''',
               fname='privacy.html')
Exemple #10
0
def process():
    print('generating html: group compare ...')
    print('  lists')
    base_custom = mylib.path_out('compare')
    title_custom = 'Compare'
    arr = []
    for list_id, json in mylib.enum_custom_lists('groupby_'):
        try:
            if json['hidden']:
                continue
        except KeyError:
            pass
        list_name = json['name']
        print('    ' + list_name)
        grp_count = len(json['groups'])
        app_count = sum([len(x['apps']) for x in json['groups']])
        try:
            desc = json['desc']
        except KeyError:
            desc = None
        arr.append((list_id, list_name, grp_count, app_count, desc))
        write_groupby_single(base_custom, list_id, list_name, title_custom)

    print('  index page')
    mylib.sort_by_name(arr, 1)
    src = f'''
<h2>{HTML.a_path([('/results/', 'Results')], title_custom)}</h2>
<p class="squeeze">
  Comparison groups do not compare a single application against another.
  Instead comparison groups cluster multiple applications into a single, logical group.
  For example, paid-vs-free apps could be a comparison group.
</p>
<div>'''
    for x in arr:
        src += HTML.h4_a_title_sub_desc(x[0], x[1],
                                        f'has {x[2]} groups with {x[3]} apps',
                                        x[4])
    HTML.write(base_custom, src + '</div>', title=title_custom)
    print('')
Exemple #11
0
def process(app_count, dom_count, inclStatic=False):
    print('generating root html ...')
    if inclStatic:
        print('  index.html')
        gen_root()  # root index.thml
        print('  redirect.html')
        gen_redirect()  # root redirect.html?id=my.bundle.id
        print('  404.html')
        gen_404()
        print('  imprint.html')
        gen_imprint()
        print('  privacy.html')
        gen_privacy()
        print('  app-privacy.html')
        gen_appprivacy()
    # print('  /help/')  # dynamic content
    # gen_help()
    print('  /results/')  # dynamic content
    gen_results(mylib.path_out('results'),
                app_count,
                dom_count,
                title='Results')
    print('')
Exemple #12
0
def gen_html_trinity(idx_dir, app_count, json, title, symlink):
    list1 = [(dom, len(ids)) for dom, ids in json['subdom'].items()]
    list2 = [(dom, len(ids)) for dom, ids in json['pardom'].items()]

    def write_index(fname, title, button):
        HTML.write(idx_dir, '<h2>{}</h2>{}{}'.format(
            HTML.a_path([('/results/', 'Results')], title),
            dropdown_choose(button), duo_list(list1, list2)
        ), title=title, fname=fname)

    # Full list (A–Z)
    list1.sort(key=lambda x: x[0])
    list2.sort(key=lambda x: x[0])
    write_index('by_name.html', title='{} (A–Z)'.format(title),
                button='Full list (A–Z)')
    # Full list (by count)
    list1.sort(key=lambda x: -x[1])
    list2.sort(key=lambda x: -x[1])
    write_index('by_count.html', title='{} (by count)'.format(title),
                button='Full list (by count)')
    # Top 10
    gen_html_top_10(idx_dir, list2[:25], app_count, 'Top 25 {}'.format(title))
    mylib.symlink(symlink, mylib.path_out(idx_dir, 'data.json'))
Exemple #13
0
def process():
    # bundle_combine assures domain name is [a-zA-Z0-9.-]
    print('generating html: domain-index ...')
    json = index_domains.loadAll()
    app_count = index_domains.number_of_apps(json)
    dom_count = len(json['subdom'])

    # Prepare for lookup
    names = [[x, index_app_names.get_name(x)] for x in json['bundle']]
    dest_dir = mylib.path_out('results')
    mylib.mkdir(dest_dir)
    mylib.json_write(mylib.path_add(dest_dir, 'lookup-apps.json'), names)
    mylib.symlink(index_domains.fname_dom_subdoms(),
                  mylib.path_add(dest_dir, 'subdoms.json'))
    names = None

    print('  Lookup')
    gen_lookup(mylib.path_out('domain'), json['pardom'], True,
               title='Domain Lookup')
    gen_lookup(mylib.path_out('subdomain'), json['subdom'], False,
               title='Subdomain Lookup')

    print('  All Domains')
    for key in ['subdom', 'pardom']:
        for x in json[key].keys():
            json[key][x] = json[key][x][1:]
    gen_html_trinity(mylib.path_out('index', 'domains', 'all'), app_count,
                     json=json, title='Requested Domains',
                     symlink=index_domains.fname_all())
    json = None

    print('  Trackers Only')
    gen_html_trinity(mylib.path_out('index', 'domains', 'tracker'), app_count,
                     json=index_domains.loadTracker(), title='Tracker',
                     symlink=index_domains.fname_tracker())

    print('  Highly Used')
    gen_html_trinity(mylib.path_out('index', 'domains', 'highly-used'),
                     app_count, json=index_domains.loadNonTracker(),
                     title='Highly Used Domains',
                     symlink=index_domains.fname_no_tracker())
    print('')
    return app_count, dom_count
Exemple #14
0
def gen_root():
    with open(mylib.path_root('templates', 'root.html'), 'r') as fp:
        HTML.write(mylib.path_out(), fp.read())
Exemple #15
0
def gen_404():
    HTML.write(mylib.path_out(),
               '''
<h2>404 – Not Found</h2>
<p>Go back to <a href="/">start page</a></p>''',
               fname='404.html')