summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--backend/helpers.py15
-rw-r--r--backend/legacy/library.js8
-rw-r--r--backend/main.py11
-rw-r--r--frontend/src/components/store/Store.tsx28
-rw-r--r--frontend/src/index.tsx37
-rw-r--r--frontend/src/plugin-loader.tsx15
-rw-r--r--frontend/src/updater.ts2
7 files changed, 95 insertions, 21 deletions
diff --git a/backend/helpers.py b/backend/helpers.py
index a75f1075..e8c2ce5b 100644
--- a/backend/helpers.py
+++ b/backend/helpers.py
@@ -1,7 +1,20 @@
+from aiohttp.web import middleware, Response
import ssl
import certifi
+import uuid
ssl_ctx = ssl.create_default_context(cafile=certifi.where())
+csrf_token = str(uuid.uuid4())
+
def get_ssl_context():
- return ssl_ctx \ No newline at end of file
+ return ssl_ctx
+
+def get_csrf_token():
+ return csrf_token
+
+@middleware
+async def csrf_middleware(request, handler):
+ if str(request.method) == "OPTIONS" or request.headers.get('Authentication') == csrf_token or str(request.rel_url) == "/auth/token" or str(request.rel_url).startswith("/plugins/load_main/") or str(request.rel_url).startswith("/static/") or str(request.rel_url).startswith("/legacy/") or str(request.rel_url).startswith("/steam_resource/"):
+ return await handler(request)
+ return Response(text='Forbidden', status='403') \ No newline at end of file
diff --git a/backend/legacy/library.js b/backend/legacy/library.js
index f9dfe699..17f4e46f 100644
--- a/backend/legacy/library.js
+++ b/backend/legacy/library.js
@@ -8,10 +8,13 @@ window.addEventListener("message", function(evt) {
}, false);
async function call_server_method(method_name, arg_object={}) {
+ const token = await fetch("http://127.0.0.1:1337/auth/token").then(r => r.text());
const response = await fetch(`http://127.0.0.1:1337/methods/${method_name}`, {
method: 'POST',
+ credentials: "include",
headers: {
'Content-Type': 'application/json',
+ Authentication: token
},
body: JSON.stringify(arg_object),
});
@@ -40,10 +43,13 @@ async function fetch_nocors(url, request={}) {
async function call_plugin_method(method_name, arg_object={}) {
if (plugin_name == undefined)
throw new Error("Plugin methods can only be called from inside plugins (duh)");
+ const token = await fetch("http://127.0.0.1:1337/auth/token").then(r => r.text());
const response = await fetch(`http://127.0.0.1:1337/plugins/${plugin_name}/methods/${method_name}`, {
method: 'POST',
+ credentials: "include",
headers: {
- 'Content-Type': 'application/json',
+ 'Content-Type': 'application/json',
+ Authentication: token
},
body: JSON.stringify({
args: arg_object,
diff --git a/backend/main.py b/backend/main.py
index b52180ab..02cc0d56 100644
--- a/backend/main.py
+++ b/backend/main.py
@@ -20,12 +20,13 @@ from os import path
from subprocess import call
import aiohttp_cors
-from aiohttp.web import Application, run_app, static
+from aiohttp.web import Application, run_app, static, get, Response
from aiohttp_jinja2 import setup as jinja_setup
from browser import PluginBrowser
from injector import inject_to_tab, tab_has_global_var
from loader import Loader
+from helpers import csrf_middleware, get_csrf_token
from utilities import Utilities
from updater import Updater
@@ -41,9 +42,10 @@ class PluginManager:
def __init__(self) -> None:
self.loop = get_event_loop()
self.web_app = Application()
+ self.web_app.middlewares.append(csrf_middleware)
self.cors = aiohttp_cors.setup(self.web_app, defaults={
"https://steamloopback.host": aiohttp_cors.ResourceOptions(expose_headers="*",
- allow_headers="*")
+ allow_headers="*", allow_credentials=True)
})
self.plugin_loader = Loader(self.web_app, CONFIG["plugin_path"], self.loop, CONFIG["live_reload"])
self.plugin_browser = PluginBrowser(CONFIG["plugin_path"], self.web_app, self.plugin_loader.plugins)
@@ -57,6 +59,8 @@ class PluginManager:
self.loop.create_task(self.loader_reinjector())
self.loop.create_task(self.load_plugins())
self.loop.set_exception_handler(self.exception_handler)
+ self.web_app.add_routes([get("/auth/token", self.get_auth_token)])
+
for route in list(self.web_app.router.routes()):
self.cors.add(route)
self.web_app.add_routes([static("/static", path.join(path.dirname(__file__), 'static'))])
@@ -67,6 +71,9 @@ class PluginManager:
return
loop.default_exception_handler(context)
+ async def get_auth_token(self, request):
+ return Response(text=get_csrf_token())
+
async def wait_for_server(self):
async with ClientSession() as web:
while True:
diff --git a/frontend/src/components/store/Store.tsx b/frontend/src/components/store/Store.tsx
index fc95fcd5..86318fd5 100644
--- a/frontend/src/components/store/Store.tsx
+++ b/frontend/src/components/store/Store.tsx
@@ -35,6 +35,10 @@ export async function installFromURL(url: string) {
await fetch('http://localhost:1337/browser/install_plugin', {
method: 'POST',
body: formData,
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
});
}
@@ -50,6 +54,10 @@ export function requestLegacyPluginInstall(plugin: LegacyStorePlugin, selectedVe
fetch('http://localhost:1337/browser/install_plugin', {
method: 'POST',
body: formData,
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
});
}}
onCancel={() => {
@@ -75,6 +83,10 @@ export async function requestPluginInstall(plugin: StorePlugin, selectedVer: Sto
await fetch('http://localhost:1337/browser/install_plugin', {
method: 'POST',
body: formData,
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
});
}
@@ -84,12 +96,24 @@ const StorePage: FC<{}> = () => {
useEffect(() => {
(async () => {
- const res = await fetch('https://beta.deckbrew.xyz/plugins', { method: 'GET' }).then((r) => r.json());
+ const res = await fetch('https://beta.deckbrew.xyz/plugins', {
+ method: 'GET',
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
+ }).then((r) => r.json());
console.log(res);
setData(res.filter((x: StorePlugin) => x.name !== 'Example Plugin'));
})();
(async () => {
- const res = await fetch('https://plugins.deckbrew.xyz/get_plugins', { method: 'GET' }).then((r) => r.json());
+ const res = await fetch('https://plugins.deckbrew.xyz/get_plugins', {
+ method: 'GET',
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
+ }).then((r) => r.json());
console.log(res);
setLegacyData(res);
})();
diff --git a/frontend/src/index.tsx b/frontend/src/index.tsx
index 4045751f..20f71766 100644
--- a/frontend/src/index.tsx
+++ b/frontend/src/index.tsx
@@ -8,24 +8,33 @@ declare global {
importDeckyPlugin: Function;
syncDeckyPlugins: Function;
deckyHasLoaded: boolean;
+ deckyAuthToken: string;
}
}
+(async () => {
+ window.deckyAuthToken = await fetch('http://127.0.0.1:1337/auth/token').then((r) => r.text());
-window.DeckyPluginLoader?.dismountAll();
-window.DeckyPluginLoader?.deinit();
+ window.DeckyPluginLoader?.dismountAll();
+ window.DeckyPluginLoader?.deinit();
-window.DeckyPluginLoader = new PluginLoader();
-window.importDeckyPlugin = function (name: string) {
- window.DeckyPluginLoader?.importPlugin(name);
-};
+ window.DeckyPluginLoader = new PluginLoader();
+ window.importDeckyPlugin = function (name: string) {
+ window.DeckyPluginLoader?.importPlugin(name);
+ };
-window.syncDeckyPlugins = async function () {
- const plugins = await (await fetch('http://127.0.0.1:1337/plugins')).json();
- for (const plugin of plugins) {
- if (!window.DeckyPluginLoader.hasPlugin(plugin)) window.DeckyPluginLoader?.importPlugin(plugin);
- }
-};
+ window.syncDeckyPlugins = async function () {
+ const plugins = await (
+ await fetch('http://127.0.0.1:1337/plugins', {
+ credentials: 'include',
+ headers: { Authentication: window.deckyAuthToken },
+ })
+ ).json();
+ for (const plugin of plugins) {
+ if (!window.DeckyPluginLoader.hasPlugin(plugin)) window.DeckyPluginLoader?.importPlugin(plugin);
+ }
+ };
-setTimeout(() => window.syncDeckyPlugins(), 5000);
+ setTimeout(() => window.syncDeckyPlugins(), 5000);
-window.deckyHasLoaded = true;
+ window.deckyHasLoaded = true;
+})();
diff --git a/frontend/src/plugin-loader.tsx b/frontend/src/plugin-loader.tsx
index 98cb3c06..29ca326f 100644
--- a/frontend/src/plugin-loader.tsx
+++ b/frontend/src/plugin-loader.tsx
@@ -75,6 +75,10 @@ class PluginLoader extends Logger {
await fetch('http://localhost:1337/browser/uninstall_plugin', {
method: 'POST',
body: formData,
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
});
}}
onCancel={() => {
@@ -144,7 +148,12 @@ class PluginLoader extends Logger {
}
private async importReactPlugin(name: string) {
- let res = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`);
+ let res = await fetch(`http://127.0.0.1:1337/plugins/${name}/frontend_bundle`, {
+ credentials: 'include',
+ headers: {
+ Authentication: window.deckyAuthToken,
+ },
+ });
if (res.ok) {
let plugin = await eval(await res.text())(this.createPluginAPI(name));
this.plugins.push({
@@ -166,8 +175,10 @@ class PluginLoader extends Logger {
async callServerMethod(methodName: string, args = {}) {
const response = await fetch(`http://127.0.0.1:1337/methods/${methodName}`, {
method: 'POST',
+ credentials: 'include',
headers: {
'Content-Type': 'application/json',
+ Authentication: window.deckyAuthToken,
},
body: JSON.stringify(args),
});
@@ -182,8 +193,10 @@ class PluginLoader extends Logger {
async callPluginMethod(methodName: string, args = {}) {
const response = await fetch(`http://127.0.0.1:1337/plugins/${pluginName}/methods/${methodName}`, {
method: 'POST',
+ credentials: 'include',
headers: {
'Content-Type': 'application/json',
+ Authentication: window.deckyAuthToken,
},
body: JSON.stringify({
args,
diff --git a/frontend/src/updater.ts b/frontend/src/updater.ts
index 692a7a70..f499d030 100644
--- a/frontend/src/updater.ts
+++ b/frontend/src/updater.ts
@@ -14,8 +14,10 @@ export interface DeckyUpdater {
export async function callUpdaterMethod(methodName: string, args = {}) {
const response = await fetch(`http://127.0.0.1:1337/updater/${methodName}`, {
method: 'POST',
+ credentials: 'include',
headers: {
'Content-Type': 'application/json',
+ Authentication: window.deckyAuthToken,
},
body: JSON.stringify(args),
});