Skip to content

Commit 1468474

Browse files
committed
Rewrite of Chromium OS2display activation script in progress
1 parent af196d6 commit 1468474

File tree

2 files changed

+179
-169
lines changed

2 files changed

+179
-169
lines changed

os2borgerpc_kiosk/os2borgerpc_kiosk/auto_activate_chromium.py

-169
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
#!/usr/bin/env python3
2+
3+
# """
4+
# Activates an OS2display screen.
5+
# Arguments: [url, activation_code]
6+
# """
7+
#
8+
# __copyright__ = "Copyright 2022, Magenta Aps"
9+
# __credits__ = ["Allan Grauenkjaer"]
10+
# __license__ = "GPL"
11+
12+
# What it does:
13+
# When activating a screen you type in an activation code and a token and
14+
# a uuid is saved to local storage, and as a result the slideshow starts
15+
# and it will persist across reboots.
16+
# This script replicates that with a POST request, and saving it to Chromiums
17+
# storage via plyvel.
18+
19+
# Ideas for changes: If updating from 16.04 .config/chromium can be deleted.
20+
21+
import os
22+
import sys
23+
import subprocess
24+
from urllib.parse import urlparse
25+
import re
26+
import requests
27+
from time import sleep
28+
29+
30+
def activate(url, api_key, activation_code):
31+
# Manual test:
32+
# curl --insecure --data 'activationCode={activation_code_here}&apikey=middleware-main-api-key' {url_here}/proxy/screen/activate
33+
data = {"activationCode": activation_code, "apikey": api_key}
34+
# verify=False in case their ssl certificate is invalid which my test site's was at least
35+
resp = requests.post(url + "/proxy/screen/activate", json=data, verify=False)
36+
37+
print(f"Response status code: {resp.status_code}")
38+
print(f"Response text: {resp.text}")
39+
40+
# It might have some invalid characters that json.loads dislikes
41+
token = resp.json()["token"]
42+
43+
print(f"Token: {token}")
44+
45+
return (resp.status_code, token)
46+
47+
48+
username = "chrome"
49+
50+
subprocess.call([sys.executable, "-m", "pip", "install", "plyvel"])
51+
52+
print("Installed plyvel.")
53+
54+
# Ignore E402 "module level import not at top of file"
55+
# It isn't at the top because plyvel hasn't been installed at that point.
56+
import plyvel # noqa: E402
57+
58+
59+
if len(sys.argv) == 3:
60+
url = sys.argv[1]
61+
# Remove trailing slash if the user typed the URL in with one
62+
if url[-1] == "/":
63+
url = url[:-1]
64+
activation_code = sys.argv[2]
65+
print(f"URL: {url}")
66+
print(f"Activation Code: {activation_code}")
67+
else:
68+
print("Missing input parameters.")
69+
exit(1)
70+
71+
# FETCHING THE API KEY
72+
CONFIG_URL = "/app/config.js"
73+
resp_config = requests.get(url + CONFIG_URL, verify=False)
74+
print(f"Status code response from {CONFIG_URL}: {resp_config.status_code}")
75+
76+
if resp_config.status_code == 200:
77+
api_key_match = re.search(r'(?<="apikey": ")[^"]+', resp_config.text)
78+
79+
if not api_key_match:
80+
print(
81+
"Failed to find the API Key in the output from {url}{CONFIG_URL}. Exiting."
82+
)
83+
exit(1)
84+
else:
85+
api_key = api_key_match.group()
86+
print(f"API KEY: {api_key}")
87+
else:
88+
print(
89+
f"Request to {CONFIG_URL} failed, which is required to fetch the API key. Exiting."
90+
)
91+
exit(1)
92+
93+
# Stepwise process
94+
# 1. Attempt to activate to get the token related to this activationCode
95+
# 2. Kick other screens using this activation code (normally you're asked in a popup to continue or not)
96+
# 3. Now authenticate again, just like step one, but this time uninterrupted because no other screen is using it
97+
98+
resp_status_code, temp_token = activate(url, api_key, activation_code)
99+
100+
if resp_status_code != 200:
101+
print(
102+
"An existing screen is activated using the activation code. Attempting to kick it:"
103+
)
104+
105+
# Kick existing screens using this code
106+
kick_url = "/proxy/screen/kick"
107+
headers = {"Authorization": f"Bearer {temp_token}"}
108+
data_kick = {"token": temp_token}
109+
resp = requests.post(url + kick_url, json=data_kick, verify=False, headers=headers)
110+
if resp.status_code != 200:
111+
print("Failed to kick the existing screen using the activation code.")
112+
print(f"Status code received was: {resp.status_code}")
113+
print(f"Data sent was: {data_kick}")
114+
print(f"URL was: {url}{kick_url}")
115+
print("Data received was:")
116+
print(resp.text)
117+
print("Exiting")
118+
exit(1)
119+
else:
120+
print("Existing screen kicked successfully. Attempting to activate it again.")
121+
122+
# ...and now activate again, which produces a different token:
123+
resp_status_code, token = activate(url, api_key, activation_code)
124+
125+
if resp_status_code != 200:
126+
print("The server couldn't activate the screen correctly. Exiting.")
127+
print(f"Status code was: {resp_status_code}")
128+
exit(1)
129+
else:
130+
print(
131+
"Screen activated correctly with the API. About to update local storage leveldb with the information:"
132+
)
133+
else:
134+
print(
135+
"Activation code not currently in use. No need to kick any existing screens using it."
136+
)
137+
token = temp_token
138+
139+
# The value of the uuid seemingly doesn't matter - it changes between calls
140+
# uuid = "randomstring"
141+
uuid = "1Nlv3s4w4dybf" # Actual example from a manual activation
142+
143+
# Making sure all instances of Chromium are shut down,
144+
# or leveldb will be inaccessible to plyvel
145+
# chromium's binary is also called chrome
146+
subprocess.call("killall chrome", shell=True)
147+
sleep(5)
148+
149+
db_path = f"/home/{username}/snap/chromium/common/chromium/Default/Local Storage/"
150+
if not os.path.exists(db_path):
151+
os.makedirs(db_path)
152+
153+
db_name = "leveldb/"
154+
db_path += db_name
155+
print(f"Connecting to leveldb db_path: {db_path}")
156+
157+
parsed_url = urlparse(url)
158+
url_key = parsed_url.scheme + "://" + parsed_url.netloc
159+
160+
# If not working try adding compression=None
161+
db = plyvel.DB(db_path, create_if_missing=True)
162+
db.put(
163+
b"_" + bytes(url_key, "ascii") + b"\x00\x01indholdskanalen_uuid",
164+
b"\x01" + bytes(uuid, "ascii"),
165+
sync=True,
166+
)
167+
db.put(
168+
b"_" + bytes(url_key, "ascii") + b"\x00\x01indholdskanalen_token",
169+
b"\x01" + bytes(token, "ascii"),
170+
sync=True,
171+
)
172+
173+
db.close()
174+
175+
# Set the proper permissions on leveldb, as in some cases some files are now
176+
# root owned which is no good, when chromium runs as a regular user:
177+
subprocess.call(["chown", "-R", f"{username}:{username}", db_path])
178+
179+
print("DB updated and connection closed.")

0 commit comments

Comments
 (0)