.
675 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Deutsche Bahn Wlan Manager
2 |
3 | This program will monitor your wireless,
4 | and keep you logged into the different wlans of the DB
5 |
6 |
7 | ## What's working?
8 | - Keeps you logged in
9 | - Keeping track of your spent data.
10 | Wifis:
11 | - WIFIOnICE/WIFI@DB (ICE-Wlan National?)
12 | - DBLounge (Lounge im Bahnhof)
13 | - CDWifi (Wifi in Czech-Trains)
14 | - Wifi@DB (Sammel-Wlan verschiedener Icomera-User)
15 | - not yet implemented
16 | -
17 |
18 |
19 | ## What's not yet working?
20 | - International/some ICEs have a JSON-API for quota.
21 | I did not ride enough in those...
22 | - "Free @Bahnhofs Wlan"-Ding?
23 |
24 | ## How do you use it?
25 | Start with:
26 |
27 | ``` bash
28 | python3 manager.py [ssid]
29 | ```
30 |
31 | Use the `-b` flag for batch mode, which means it only tries to log you in and terminate.
32 | It will check the SSID automatically via `ìw`, but it can be fixed via an argument.
33 |
34 | ### Network-Manager
35 | To use it with *network-manager*, go to the *network-manager* directory and `sudo ./install.sh`
36 | If you connect with *network-manager* to a DB wifi, the tool will start in the background automatically and log the output to `/var/log/dbwifi`.
37 |
38 | ## Dependencies
39 | - python3-dnspython
40 | - python3-bs4 (beautifulsoup)
41 |
42 | ### Install Dependencies on Ubuntu
43 | ``` bash
44 | sudo apt-get install python3 python3-bs4 python3-dnspython
45 | ```
46 |
--------------------------------------------------------------------------------
/db_cdwifi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import requests
4 | import logging
5 | import json
6 | import re
7 |
8 | logging.getLogger("requests").setLevel(logging.WARNING)
9 |
10 |
11 | class DBCDWiFiManager:
12 | SSID = "CDWiFi"
13 | api_host = "www.info.cdwifi.cz"
14 | api_host_limit = "cdwifi.cz"
15 | api_site = "api/jsonp/connectivity"
16 |
17 | def __init__(self):
18 | self.quota = None
19 |
20 | self.is_online = None
21 |
22 | self.json_decoder = json.JSONDecoder()
23 | self.session = requests.Session()
24 | self.csrf_token = None
25 |
26 | def get_quota(self):
27 | return self.quota if self.quota else 0
28 |
29 | def _make_request(self, url, protocol='http'):
30 | try:
31 | return self.session.get('{}://{}'.format(protocol, url), timeout=5, verify=False)
32 | except requests.Timeout:
33 | return False
34 | except requests.ConnectionError as e:
35 | logging.warning('Connection Error: {}'.format(e))
36 | return False
37 |
38 | def update_online(self):
39 | on = self.update_online_api()
40 | if on is False:
41 | if self.is_online is True or self.is_online is None:
42 | logging.info('I am not online anymore! :(')
43 | self.is_online = False
44 | elif on is True:
45 | if self.is_online is False or self.is_online is None:
46 | logging.info('I am online again! :)')
47 | self.is_online = True
48 |
49 | @staticmethod
50 | def _get_csrf(text):
51 | search_string = 'name="CSRFToken" value="'
52 | pos = text.find(search_string)
53 | return text[pos+len(search_string): pos+len(search_string)+32]
54 |
55 | def update_online_api(self):
56 | status = self._get_status_from_api()
57 | if status.get('online') == "1":
58 | self.update_quota()
59 | return True
60 |
61 | def update_quota(self):
62 | ret = self._make_request('{}/{}'.format(self.api_host_limit, 'portal/api/vehicle/gateway/data/limit'))
63 | if ret and ret.status_code == 200:
64 | try:
65 | api_response = ret.json()
66 | quota = api_response.get('usedAmount', 0)
67 | limit = api_response.get('totalLimit', 1)
68 | if type(quota) is int and type(limit) is int:
69 | self.quota = float('{:.2f}'.format(1.0*quota/limit))
70 | except Exception as e:
71 | logging.exception('Error while updating quote: {}'.format(e))
72 | return
73 |
74 | def _get_status_from_api(self):
75 | ret = self._make_request('{}/{}'.format(self.api_host, self.api_site))
76 | if ret and ret.status_code == 200:
77 | return self.json_decoder.decode(re.sub(r'[\n\(\); ]', '', ret.text[1:-2]))
78 | return {}
79 |
80 | def login(self):
81 | """ Log in to the ICE Portal (wifionice) """
82 | logging.info('Trying to log in...')
83 | try:
84 | ret = self.session.post('http://{}/{}'.format(self.api_host, 'portal/api/vehicle/gateway/user/authenticate'))
85 | if ret.status_code in [200, 500]: # yes, apparently 500 is okay, too ;)
86 | return True
87 | except requests.exceptions.ConnectionError:
88 | logging.debug('Login Failed, probably bad wifi')
89 |
90 |
91 | if __name__ == '__main__':
92 | w = DBCDWiFiManager()
93 | w.update_online()
94 | print(w.is_online)
--------------------------------------------------------------------------------
/db_generic_manager.py:
--------------------------------------------------------------------------------
1 | import requests
2 | import json
3 | import logging
4 |
5 |
6 | class DBManager:
7 | """
8 | The Interface all managers have to comply to.
9 | """
10 | def __init__(self):
11 | self.quota = None
12 |
13 | self.is_online = None
14 |
15 | self.json_decoder = json.JSONDecoder()
16 | self.session = requests.Session()
17 | self.csrf_token = None
18 |
19 | def get_quota(self):
20 | return self.quota if self.quota else 0
21 |
22 | def _make_request(self, url, protocol='http'):
23 | try:
24 | return self.session.get('{}://{}'.format(protocol, url), timeout=5, verify=False)
25 | except requests.Timeout:
26 | return False
27 | except requests.ConnectionError as e:
28 | logging.warning('Connection Error: {}'.format(e))
29 | return False
30 |
31 | def update_online(self):
32 | on = self._update_online_api()
33 | if on is False:
34 | if self.is_online is True or self.is_online is None:
35 | logging.info('I am not online anymore! :(')
36 | self.is_online = False
37 | elif on is True:
38 | if self.is_online is False or self.is_online is None:
39 | logging.info('I am online again! :)')
40 | self.is_online = True
41 |
42 | def login(self):
43 | return NotImplementedError
44 |
45 | def _update_online_api(self):
46 | return NotImplementedError
47 |
--------------------------------------------------------------------------------
/db_lounge.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import bs4
4 | import re
5 | import requests
6 | import logging
7 |
8 | logging.getLogger("requests").setLevel(logging.WARNING)
9 |
10 |
11 | class DBLoungeManager:
12 | SSID = "DBLounge"
13 | api_host = "www.hotsplots.de"
14 | api_site = "/auth/login.php"
15 |
16 |
17 | def __init__(self):
18 | self.quota = None
19 |
20 | self.is_online = None
21 |
22 | self.session = requests.Session()
23 | self.challenge = None
24 | self.last_portal_soup = None
25 |
26 | # No custom DNS here, since DBLounges have non-equal address-spaces
27 |
28 | def get_quota(self):
29 | return self.quota if self.quota else 0
30 |
31 | def _make_request(self, url, protocol='https'):
32 | try:
33 | return self.session.get('{}://{}'.format(protocol, url), timeout=5)
34 | except requests.Timeout:
35 | return None
36 | except requests.ConnectionError as e:
37 | logging.warning('Connection Error: {}'.format(e))
38 | return None
39 |
40 | def update_online(self):
41 | ret = self._make_request("detectportal.firefox.com/success.txt", protocol="http")
42 | if ret is None:
43 | return
44 | # if "Forbidden access" in ret.text:
45 | # Redirect failed?
46 | # print(ret.statuscode)
47 | if ret.text.strip() == 'success':
48 | if self.is_online is False or self.is_online is None:
49 | logging.info('I am online again! :)')
50 | self.is_online = True
51 | else:
52 | if self.is_online is True or self.is_online is None:
53 | logging.info('I am not online anymore! :(')
54 | self.is_online = False
55 | self.last_portal_soup = bs4.BeautifulSoup(ret.text, 'lxml')
56 |
57 | def update_quota(self, user):
58 | if type(user) is dict:
59 | quota = user.get('data_download_used', '')
60 | limit = user.get('data_download_limit', '')
61 | if quota.isdigit() and limit.isdigit():
62 | self.quota = 1.0*quota/limit
63 | else:
64 | ret = self._make_request('{}/{}'.format(self.api_host, self.api_site), protocol='http')
65 | if ret:
66 | try:
67 | self.quota = float(ret.text)
68 | except ValueError:
69 | pass
70 |
71 | def login(self):
72 | """ Log in to the Lounge Portal """
73 | logging.info('Trying to log in...')
74 |
75 | print(self.last_portal_soup)
76 | data = {item.attrs.get('name'): item.attrs.get('value')
77 | for item in self.last_portal_soup.find_all('input', attrs={'type': 'hidden'})}
78 |
79 | data['termsOK'] = True
80 | data["button"] = "kostenlos einloggen"
81 |
82 | headers = {
83 | "Content-Type": "application/x-www-form-urlencoded"
84 | }
85 | try:
86 | ret = self.session.post('https://{}/{}'.format(self.api_host, self.api_site),
87 | data=data, headers=headers)
88 | if ret.text.find('loading.gif'):
89 | self.confirm_login(ret)
90 | except requests.exceptions.ConnectionError:
91 | logging.debug('Login Failed, probably bad wifi')
92 |
93 | def confirm_login(self, login_ret):
94 | confirm_soup = bs4.BeautifulSoup(login_ret.text, 'lxml')
95 | refresh = confirm_soup.find('meta', attrs={'http-equiv': "refresh"})
96 | if refresh:
97 | content = refresh.attrs.get('content')
98 | confirm_url = content[len('0;url='):]
99 | if confirm_url:
100 | try:
101 | ret = self.session.get(confirm_url)
102 | if ret.text.find(""):
103 | logging.info('Login Successful!')
104 | return
105 | except requests.exceptions.ConnectionError:
106 | logging.debug('Login Confirm Failed, probably bad wifi')
107 |
108 | logging.warning("Return from Portal malformed! Did the DB-Lounge website change?")
109 |
--------------------------------------------------------------------------------
/db_wifiatdb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import requests
4 | import logging
5 | import re
6 |
7 | from db_wifiatdb_suewex import DBWifiAtDBSuewex
8 | from db_wifiatdb_publicwifi import DBWifiAtDBPublicWifi
9 |
10 | logging.getLogger("requests").setLevel(logging.WARNING)
11 |
12 |
13 | class DBWifiAtDBDecider:
14 | """
15 | Wifi@DB is used by many different providers, only differing the captive portal.
16 |
17 | Therefore, we check the captive portal here to decide which provider works for
18 | the specific portal, if we know any.
19 | """
20 | SSID = "Wifi@DB"
21 | PROVIDERS = {
22 | DBWifiAtDBSuewex.URL: DBWifiAtDBSuewex,
23 | DBWifiAtDBPublicWifi.URL: DBWifiAtDBPublicWifi,
24 | }
25 |
26 | def get_specific_provider(self):
27 | ret = requests.get('detectportal.firefox.com/success.txt')
28 | if ret.ok:
29 | if ret.text == 'success':
30 | logging.warning('Already logged in, cannot determine which Portal we are connected to')
31 | return None
32 |
33 | base_url = re.search(r'https?://(.+)/', ret.url)
34 | if not base_url:
35 | logging.error('Cannot get base_url, portal is: {}'.format(ret.url))
36 | return None
37 |
38 | base_url = base_url.group(1)
39 | provider = self.PROVIDERS.get(base_url)
40 | if provider is None:
41 | logging.warning("No specific provider implemented yet for this WIFI@DB :(")
42 | return provider
43 |
44 |
45 | if __name__ == '__main__':
46 | w = DBWifiAtDBDecider().get_specific_provider()()
47 | w.update_online()
48 | print(w.is_online)
49 |
--------------------------------------------------------------------------------
/db_wifiatdb_publicwifi.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import requests
4 | import logging
5 | import json
6 | import re
7 |
8 | logging.getLogger("requests").setLevel(logging.WARNING)
9 |
10 |
11 | class DBWifiAtDBPublicWifi:
12 | URL = "public-wifi.deutschebahn.com"
13 | login_url = ""
14 | # api_host = "www.ombord.info"
15 | # api_host_limit = ""
16 | # api_site = "api/jsonp/user"
17 |
18 | def login(self):
19 | """ Log in to the Portal """
20 | logging.info('Trying to log in...')
21 | """First Call: (idk if necessary?)
22 | action subscribe
23 | type one
24 | connect_policy_accept true
25 | user_login
26 | user_password
27 | user_password_confirm
28 | email_address
29 | prefix
30 | phone
31 | policy_accept false
32 | gender
33 | interests
34 | """
35 | """Second Call:
36 | action authenticate
37 | login arw005o
38 | password 5QMu7v6o
39 | policy_accept true
40 | from_ajax true
41 | wispr_mode false
42 | """
43 | #ret = self._make_request(self.login_url)
44 | #return ret and ret.ok
45 |
46 | def _update_online_api(self):
47 | id_ = self._get_id()
48 | return True #FIXME: not able to get quota, but any request against the login_url logs in, so...
49 | print(id_)
50 | status = self._get_status_from_api(id_)
51 | if status.get('online') == "1":
52 | self.update_quota(status)
53 | return True
54 |
55 | def _get_id(self):
56 | ret = self._make_request(self.login_url)
57 | if ret and ret.ok:
58 | result = re.search(r'https://{}/{}/\?callback=(jQuery.*?)">'.format(self.api_host, self.api_site), ret.text)
59 | if result:
60 | return result.group(1).replace('&', '&')
61 |
62 |
63 | # def update_quota(self):
64 | # Example API Callback
65 |
66 | # ret = self._make_request('{}/{}'.format(self.api_host_limit, 'portal/api/vehicle/gateway/data/limit'))
67 | # if ret and ret.status_code == 200:
68 | # try:
69 | # api_response = ret.json()
70 | # quota = api_response.get('usedAmount', 0)
71 | # limit = api_response.get('totalLimit', 1)
72 | # if type(quota) is int and type(limit) is int:
73 | # self.quota = float('{:.2f}'.format(1.0*quota/limit))
74 | # except Exception as e:
75 | # logging.exception('Error while updating quote: {}'.format(e))
76 | # return
77 |
78 | def _get_status_from_api(self, id_):
79 | ret = self._make_request('{}/{}/?callback={}'.format(self.api_host, self.api_site, id_), protocol="https")
80 | print(ret.request.url)
81 | print(ret.text)
82 | if ret and ret.ok:
83 | print(ret.text)
84 | return ret.json()
85 | return {}
86 |
87 |
88 |
89 | if __name__ == '__main__':
90 | w = DBWifiAtDBManager()
91 | w.update_online()
92 | print(w.is_online)
93 |
--------------------------------------------------------------------------------
/db_wifiatdb_suewex.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import requests
4 | import logging
5 | import json
6 | import re
7 |
8 | from db_generic_manager import DBManager
9 |
10 | logging.getLogger("requests").setLevel(logging.WARNING)
11 |
12 |
13 | class DBWifiAtDBSuewex(DBManager):
14 | URL = "wifi-bahn.de"
15 | login_url = "wifi-bahn.de/connect.php"
16 | api_host = "www.ombord.info"
17 | # api_host_limit = ""
18 | api_site = "api/jsonp/user"
19 |
20 | def login(self):
21 | """ Log in to the Portal """
22 | logging.info('Trying to log in...')
23 | ret = self._make_request(self.login_url)
24 | return ret and ret.ok
25 |
26 | def _update_online_api(self):
27 | id_ = self._get_id()
28 | return True #FIXME: not able to get quota, but any request against the login_url logs in, so...
29 | print(id_)
30 | status = self._get_status_from_api(id_)
31 | if status.get('online') == "1":
32 | self.update_quota(status)
33 | return True
34 |
35 | def _get_id(self):
36 | ret = self._make_request(self.login_url)
37 | if ret and ret.ok:
38 | result = re.search(r'https://{}/{}/\?callback=(jQuery.*?)">'.format(self.api_host, self.api_site), ret.text)
39 | if result:
40 | return result.group(1).replace('&', '&')
41 |
42 |
43 | # def update_quota(self):
44 | # Example API Callback
45 | """jQuery311013181348935550807_1533860865681({
46 | "version":"1.9",
47 | "ip":"172.16.47.224",
48 | "mac":"18:1D:EA:AB:E9:51",
49 | "online":"40991",
50 | "timeleft":"40991",
51 | "authenticated":"1",
52 | "userclass":"2",
53 | "expires":"Thu Dec 26 22:26:52 2019",
54 | "timeused":"2209",
55 | "data_download_used":"9987703",
56 | "data_upload_used":"12925372",
57 | "data_total_used":"22913075",
58 | "data_download_limit":"0",
59 | "data_upload_limit":"0",
60 | "data_total_limit":"52428800",
61 | "bandwidth_download_limit":"81250",
62 | "bandwidth_upload_limit":"81250",
63 | "cap_level":"0"
64 | });"""
65 | # ret = self._make_request('{}/{}'.format(self.api_host_limit, 'portal/api/vehicle/gateway/data/limit'))
66 | # if ret and ret.status_code == 200:
67 | # try:
68 | # api_response = ret.json()
69 | # quota = api_response.get('usedAmount', 0)
70 | # limit = api_response.get('totalLimit', 1)
71 | # if type(quota) is int and type(limit) is int:
72 | # self.quota = float('{:.2f}'.format(1.0*quota/limit))
73 | # except Exception as e:
74 | # logging.exception('Error while updating quote: {}'.format(e))
75 | # return
76 |
77 | def _get_status_from_api(self, id_):
78 | ret = self._make_request('{}/{}/?callback={}'.format(self.api_host, self.api_site, id_), protocol="https")
79 | print(ret.request.url)
80 | print(ret.text)
81 | if ret and ret.ok:
82 | print(ret.text)
83 | return ret.json()
84 | return {}
85 |
--------------------------------------------------------------------------------
/db_wifionice.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import requests
4 | import logging
5 | import dns.resolver
6 | import json
7 | import re
8 |
9 | from db_generic_manager import DBManager
10 |
11 | logging.getLogger("requests").setLevel(logging.WARNING)
12 |
13 |
14 | class DBWifiOnICEManager(DBManager):
15 | SSID = "WIFIonICE"
16 | SSID_secondary = "WIFI@DB"
17 | api_host = "www.wifionice.de"
18 | api_site = "usage_info/"
19 | api_host_new = "www.ombord.info"
20 | api_site_new = "api/jsonp/user"
21 |
22 | def __init__(self):
23 | super().__init__()
24 | self.quota = None
25 |
26 | self.is_online = None
27 | self.new_api = None
28 |
29 | self.json_decoder = json.JSONDecoder()
30 | self.session = requests.Session()
31 | self.csrf_token = None
32 |
33 | self.resolver = dns.resolver.Resolver()
34 | self.resolver.nameservers = ['172.18.0.1']
35 | try:
36 | self.api_host_ip = self.resolve_url(self.api_host)
37 | self.api_host_new_ip = self.resolve_url(self.api_host_new)
38 | except dns.exception.Timeout:
39 | self.api_host_ip = "172.18.0.1"
40 | self.api_host_new_ip = "172.18.0.1"
41 |
42 | def get_quota(self):
43 | quota = 0
44 | if self.quota:
45 | quota = self.quota
46 |
47 | return quota
48 |
49 | def _make_request(self, url, protocol='https'):
50 | try:
51 | return self.session.get('{}://{}'.format(protocol, url), timeout=5, verify=False)
52 | except requests.Timeout:
53 | return False
54 | except requests.ConnectionError as e:
55 | logging.warning('Connection Error: {}'.format(e))
56 | return False
57 |
58 | def _check_api(self):
59 | logging.info('Checking API version...')
60 | ret = self._make_request(self.api_host_new_ip)
61 | if ret is not None:
62 | if ret and ret.status_code != 404 and len(ret.text) > 60:
63 | self.new_api = True
64 | logging.info('Using new API.')
65 | else:
66 | self.new_api = False
67 | logging.info('Using old API.')
68 |
69 | return self.new_api
70 |
71 | def update_online(self):
72 | if self.new_api is None:
73 | if self._check_api() is None:
74 | print('api none')
75 | return
76 |
77 | on = self.update_online_new_api() if self.new_api else self.update_online_old_api()
78 | if on is False:
79 | if self.is_online is True or self.is_online is None:
80 | logging.info('I am not online anymore! :(')
81 | self.is_online = False
82 | elif on is True:
83 | if self.is_online is False or self.is_online is None:
84 | logging.info('I am online again! :)')
85 | self.is_online = True
86 |
87 | def update_online_old_api(self):
88 | """ Check if we are online. Don't change the state if the check fails itself """
89 | ret = self._make_request('{}/de/'.format(self.api_host_ip), protocol='http')
90 | if ret and ret.status_code == 200:
91 | if 'Data meter header' in ret.text:
92 | self.update_quota(ret.text)
93 | else:
94 | self.quota = 0.0
95 |
96 | self.csrf_token = self._get_csrf(ret.text)
97 |
98 | txt = ret.text.lower()
99 | if txt.count('offline') > 5:
100 | return False
101 | if txt.count('online') > 5:
102 | return True
103 | else:
104 | logging.debug('Return object from wifionice broken!: {}'.format(ret))
105 |
106 | @staticmethod
107 | def _get_csrf(text):
108 | search_string = 'name="CSRFToken" value="'
109 | pos = text.find(search_string)
110 | return text[pos+len(search_string): pos+len(search_string)+32]
111 |
112 | def update_online_new_api(self):
113 | """
114 | "version":"1.9", "ip":"172.16.100.116", "mac":"6C:88:14:84:84:88", "online":"0", "timeleft":"0",
115 | "authenticated":"1", "userclass":"2", "expires":"Never", "timeused":"1206", "data_download_used":"9256202",
116 | "data_upload_used":"4302103", "data_total_used":"13558305", "data_download_limit":"209715200",
117 | "data_upload_limit":"0", "data_total_limit":"0", "bandwidth_download_limit":"81250",
118 | "bandwidth_upload_limit":"81250", "cap_level":"0"
119 | """
120 | status = self._get_status_from_api()
121 | print(status)
122 |
123 | self.update_quota(status)
124 |
125 | return status.get('online') == "1"
126 |
127 | def update_quota(self, api_response):
128 | if type(api_response) is dict:
129 | quota = api_response.get('data_download_used', '')
130 | limit = api_response.get('data_download_limit', '')
131 | if quota.isdigit() and limit.isdigit():
132 | self.quota = 1.0*quota/limit
133 | return
134 |
135 | if self.new_api is False:
136 | ret = self._make_request("www.wifionice.de/usage_info", 'http')
137 | if ret:
138 | try:
139 | self.quota = float(ret.text)
140 | except ValueError:
141 | pass
142 |
143 | def _get_status_from_api(self):
144 | ret = self._make_request('{}/{}'.format(self.api_host_new_ip, self.api_site_new))
145 | if ret and ret.status_code == 200:
146 | return self.json_decoder.decode(re.sub(r'[\n\(\); ]', '', ret.text)[:-2] + '}')
147 | return {}
148 |
149 | def login(self):
150 | """ Log in to the ICE Portal (wifionice) """
151 | logging.info('Trying to log in...')
152 | try:
153 | ret = self.session.post('http://{}/de/?login'.format(self.api_host_ip),
154 | data={'login': True, 'CSRFToken': self.csrf_token})
155 | except requests.exceptions.ConnectionError:
156 | logging.debug('Login Failed, probably bad wifi')
157 |
158 | def resolve_url(self, url):
159 | rrset = self.resolver.query(url).rrset
160 | return rrset.items[0].address if rrset.items else None
161 |
--------------------------------------------------------------------------------
/manager.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 |
3 | import time
4 | import logging
5 | import subprocess
6 |
7 | from db_lounge import DBLoungeManager
8 | from db_wifionice import DBWifiOnICEManager
9 | from db_cdwifi import DBCDWiFiManager
10 | from db_wifiatdb import DBWifiAtDBDecider
11 |
12 |
13 | class DBManager:
14 | managers = {
15 | DBLoungeManager.SSID: DBLoungeManager,
16 | DBWifiOnICEManager.SSID: DBWifiOnICEManager,
17 | DBWifiOnICEManager.SSID_secondary: DBWifiOnICEManager,
18 | DBCDWiFiManager.SSID: DBCDWiFiManager,
19 | DBWifiAtDBDecider.SSID: DBWifiAtDBDecider
20 | }
21 | manager = None
22 |
23 | def __init__(self, batch_mode=False, ssid=""):
24 | self.batch_mode = batch_mode
25 | if ssid:
26 | manager = self.managers.get(ssid)
27 | if manager:
28 | self.manager = manager()
29 |
30 | logging.basicConfig(level=logging.WARNING if batch_mode else logging.INFO)
31 |
32 | self.is_online = None
33 | self.new_api = None
34 |
35 | def run(self):
36 | if self.batch_mode:
37 | self.manager = self.get_login_manager()
38 | if not self.manager:
39 | return
40 |
41 | iteration_ = 5
42 | while iteration_ > 0:
43 | self.manager.update_online()
44 | print('DB: !' if not self.manager.is_online else 'DB: {:.0%}'.format(self.manager.get_quota()))
45 | if self.manager.is_online:
46 | return
47 | else:
48 | self.manager.login()
49 |
50 | time.sleep(1)
51 |
52 | iteration_ -= 1
53 | else:
54 | while not time.sleep(1):
55 | self.manager = self.get_login_manager()
56 | if not self.manager:
57 | continue
58 |
59 | self.manager.update_online()
60 | if self.manager.is_online:
61 | quota = self.manager.get_quota()
62 | if quota < 1:
63 | print('Quota: {0:.0%}\r'.format(quota), end='', flush=True)
64 | else:
65 | print("Quota surpassed, your traffic is being slowed! MAC-Change suggested")
66 | elif self.manager.is_online is None:
67 | continue
68 | else:
69 | self.manager.login()
70 |
71 | def get_login_manager(self):
72 | if self.manager is not None:
73 | return self.manager
74 |
75 | interface_ssids = []
76 | res = subprocess.run(['/bin/ip', 'a'], stdout=subprocess.PIPE)
77 | up_interfaces = [l.split(b':')[1].strip() for l in res.stdout.split(b'\n') if b"state UP" in l]
78 | for interface in up_interfaces:
79 | res = subprocess.run(['/sbin/iw', 'dev', interface, 'link'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
80 | iw_result = res.stdout.decode('utf-8')
81 | for line in iw_result.split('\n'):
82 | if line.startswith('command failed'):
83 | break
84 | if 'ssid' in line.lower():
85 | interface_ssids.append(line.strip().split()[-1])
86 | break
87 |
88 | for ssid in interface_ssids:
89 | manager = self.managers.get(ssid)
90 | if manager is None:
91 | continue
92 |
93 | if hasattr(manager, "PROVIDERS"):
94 | provider = manager()
95 | manager = provider.get_specific_provider()
96 |
97 | if type(manager) is type:
98 | # If not yet in instanciated, do
99 | manager = manager()
100 | self.managers[ssid] = manager
101 | return manager
102 |
103 |
104 | if __name__ == '__main__':
105 | import argparse
106 | argparser = argparse.ArgumentParser(description="Keeps your Wifi logged into the various DB Wifis")
107 | argparser.add_argument('-b', '--batch', action='store_true',
108 | help='Just check status and login, if not yet.')
109 | argparser.add_argument('ssid', nargs="?", type=str, help="If you already know the SSID and it's not gonna change")
110 |
111 | args = argparser.parse_args()
112 |
113 | db_manager = DBManager(batch_mode=args.batch, ssid=args.ssid)
114 | try:
115 | db_manager.run()
116 | except (KeyboardInterrupt, EOFError):
117 | pass
118 |
--------------------------------------------------------------------------------
/network-manager/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | BASEDIR=$(readlink -f $(dirname $0)/..)
3 | cp -rp ${BASEDIR} /usr/share
4 | chmod 700 /usr/share/db_wlan_manager/network-manager/network-manager-dbwifi
5 | chown root: /usr/share/db_wlan_manager/network-manager/network-manager-dbwifi
6 |
7 | ln -sf /usr/share/db_wlan_manager/network-manager/network-manager-dbwifi /etc/NetworkManager/dispatcher.d/10-dbwifi
8 |
--------------------------------------------------------------------------------
/network-manager/network-manager-dbwifi:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | case "$2" in
4 | up)
5 | ssid=$(nmcli -g TYPE,NAME connection show --active | grep -oE '802-11-wireless:(WIFIonICE|WIFI@DB|DBLounge)')
6 | if [[ $ssid ]]; then
7 | python3 /usr/share/db_wlan_manager/manager.py -b $ssid 2>&1 >> /var/log/dbwifi
8 | fi
9 | ;;
10 | down)
11 | # Nothing to do: nm will kill all it's child processes when the iface does down.
12 | ;;
13 | esac
14 |
--------------------------------------------------------------------------------