mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-09 09:57:59 +00:00
minor frontend tweaks and use javascript for managing domain bans
This commit is contained in:
parent
49917fcc4e
commit
10ba039938
|
@ -68,6 +68,8 @@ class Application(web.Application):
|
|||
for path, view in VIEWS:
|
||||
self.router.add_view(path, view)
|
||||
|
||||
self.add_routes([web.static('/static', get_resource('frontend/static'))])
|
||||
|
||||
setup_swagger(
|
||||
self,
|
||||
ui_version = 3,
|
||||
|
@ -124,6 +126,40 @@ class Application(web.Application):
|
|||
return timedelta(seconds=uptime.seconds)
|
||||
|
||||
|
||||
def get_csp(self, request: Request) -> str:
|
||||
data = [
|
||||
"default-src 'none'",
|
||||
f"script-src 'nonce-{request['hash']}'",
|
||||
f"style-src 'nonce-{request['hash']}'",
|
||||
"form-action 'self'",
|
||||
"connect-src 'self'",
|
||||
"img-src 'self'",
|
||||
"object-src 'none'",
|
||||
"frame-ancestors 'none'"
|
||||
]
|
||||
|
||||
return '; '.join(data) + ';'
|
||||
|
||||
# data = {
|
||||
# 'base-uri': '\'none\'',
|
||||
# 'default-src': '\'none\'',
|
||||
# 'frame-ancestors': '\'none\'',
|
||||
# 'font-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'img-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'style-src': f'\'self\' https://{self.config.domain} \'nonce-randomstringhere\'',
|
||||
# 'media-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'frame-src': f'\'self\' https:',
|
||||
# 'manifest-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'form-action': f'\'self\'',
|
||||
# 'child-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'worker-src': f'\'self\' https://{self.config.domain}',
|
||||
# 'connect-src': f'\'self\' https://{self.config.domain} wss://{self.config.domain}',
|
||||
# 'script-src': f'\'self\' https://{self.config.domain}'
|
||||
# }
|
||||
#
|
||||
# return '; '.join(f'{key} {value}' for key, value in data.items()) + ';'
|
||||
|
||||
|
||||
def push_message(self, inbox: str, message: Message, instance: Row) -> None:
|
||||
self['push_queue'].put((inbox, message, instance))
|
||||
|
||||
|
@ -269,6 +305,9 @@ async def handle_response_headers(request: web.Request, handler: Callable) -> Re
|
|||
resp = await handler(request)
|
||||
resp.headers['Server'] = 'ActivityRelay'
|
||||
|
||||
# if resp.content_type == 'text/html':
|
||||
# resp.headers['Content-Security-Policy'] = Application.DEFAULT.get_csp(request)
|
||||
|
||||
if not request.app['dev'] and request.path.endswith(('.css', '.js')):
|
||||
# cache for 2 weeks
|
||||
resp.headers['Cache-Control'] = 'public,max-age=1209600,immutable'
|
||||
|
|
|
@ -11,8 +11,10 @@
|
|||
%title << {{config.name}}: {{page}}
|
||||
%meta(charset="UTF-8")
|
||||
%meta(name="viewport" content="width=device-width, initial-scale=1")
|
||||
%link(rel="stylesheet" type="text/css" href="/theme/{{config.theme}}.css")
|
||||
%link(rel="stylesheet" type="text/css" href="/style.css")
|
||||
%link(rel="stylesheet" type="text/css" href="/theme/{{config.theme}}.css" nonce="{{view.request['hash']}}")
|
||||
%link(rel="stylesheet" type="text/css" href="/static/style.css" nonce="{{view.request['hash']}}")
|
||||
%script(type="application/javascript" src="/static/menu.js" nonce="{{view.request['hash']}}", defer)
|
||||
%script(type="application/javascript" src="/static/api.js" nonce="{{view.request['hash']}}", defer)
|
||||
-block head
|
||||
|
||||
%body
|
||||
|
@ -38,19 +40,18 @@
|
|||
#container
|
||||
#header.section
|
||||
%span#menu-open << ⁞
|
||||
%span.title-container
|
||||
%a.title(href="/") -> =config.name
|
||||
|
||||
-if view.request.path not in ["/", "/login"]
|
||||
.page -> =page
|
||||
|
||||
%a.title(href="/") -> =config.name
|
||||
.empty
|
||||
|
||||
-if error
|
||||
.error.section -> =error
|
||||
%fieldset.error.section
|
||||
%legend << Error
|
||||
=error
|
||||
|
||||
-if message
|
||||
.message.section -> =message
|
||||
%fieldset.message.section
|
||||
%legend << Message
|
||||
=message
|
||||
|
||||
#content(class="page-{{page.lower().replace(' ', '_')}}")
|
||||
-block content
|
||||
|
@ -69,26 +70,3 @@
|
|||
.version
|
||||
%a(href="https://git.pleroma.social/pleroma/relay")
|
||||
ActivityRelay/{{version}}
|
||||
|
||||
%script(type="application/javascript")
|
||||
const body = document.getElementById("container")
|
||||
const menu = document.getElementById("menu");
|
||||
const menu_open = document.getElementById("menu-open");
|
||||
const menu_close = document.getElementById("menu-close");
|
||||
|
||||
menu_open.addEventListener("click", (event) => {
|
||||
var new_value = menu.attributes.visible.nodeValue === "true" ? "false" : "true";
|
||||
menu.attributes.visible.nodeValue = new_value;
|
||||
});
|
||||
|
||||
menu_close.addEventListener("click", (event) => {
|
||||
menu.attributes.visible.nodeValue = "false"
|
||||
});
|
||||
|
||||
body.addEventListener("click", (event) => {
|
||||
if (event.target === menu_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
menu.attributes.visible.nodeValue = "false";
|
||||
});
|
||||
|
|
|
@ -2,24 +2,26 @@
|
|||
-set page="Config"
|
||||
-import "functions.haml" as func
|
||||
-block content
|
||||
%form.section(action="/admin/config" method="POST")
|
||||
.grid-2col
|
||||
%label(for="name") << Name
|
||||
%input(id = "name" name="name" placeholder="Relay Name" value="{{config.name or ''}}")
|
||||
%fieldset.section
|
||||
%legend << Config
|
||||
%form(action="/admin/config" method="POST")
|
||||
.grid-2col
|
||||
%label(for="name") << Name
|
||||
%input(id = "name" name="name" placeholder="Relay Name" value="{{config.name or ''}}")
|
||||
|
||||
%label(for="description") << Description
|
||||
%textarea(id="description" name="note" value="{{config.note or ''}}") << {{config.note}}
|
||||
%label(for="description") << Description
|
||||
%textarea(id="description" name="note" value="{{config.note or ''}}") << {{config.note}}
|
||||
|
||||
%label(for="theme") << Color Theme
|
||||
=func.new_select("theme", config.theme, themes)
|
||||
%label(for="theme") << Color Theme
|
||||
=func.new_select("theme", config.theme, themes)
|
||||
|
||||
%label(for="log-level") << Log Level
|
||||
=func.new_select("log-level", config.log_level.name, levels)
|
||||
%label(for="log-level") << Log Level
|
||||
=func.new_select("log-level", config.log_level.name, levels)
|
||||
|
||||
%label(for="whitelist-enabled") << Whitelist
|
||||
=func.new_checkbox("whitelist-enabled", config.whitelist_enabled)
|
||||
%label(for="whitelist-enabled") << Whitelist
|
||||
=func.new_checkbox("whitelist-enabled", config.whitelist_enabled)
|
||||
|
||||
%label(for="approval-required") << Approval Required
|
||||
=func.new_checkbox("approval-required", config.approval_required)
|
||||
%label(for="approval-required") << Approval Required
|
||||
=func.new_checkbox("approval-required", config.approval_required)
|
||||
|
||||
%input(type="submit" value="Save")
|
||||
%input(type="submit" value="Save")
|
||||
|
|
|
@ -1,48 +1,53 @@
|
|||
-extends "base.haml"
|
||||
-set page="Domain Bans"
|
||||
|
||||
-block head
|
||||
%script(type="application/javascript" src="/static/domain_ban.js" nonce="{{view.request['hash']}}", defer)
|
||||
|
||||
-block content
|
||||
%details.section
|
||||
%summary << Ban Domain
|
||||
%form(action="/admin/domain_bans" method="POST")
|
||||
#add-item
|
||||
%label(for="domain") << Domain
|
||||
%input(type="domain" id="domain" name="domain" placeholder="Domain")
|
||||
#add-item
|
||||
%label(for="new-domain") << Domain
|
||||
%input(type="domain" id="new-domain" name="domain" placeholder="Domain")
|
||||
|
||||
%label(for="reason") << Ban Reason
|
||||
%textarea(id="reason" name="reason") << {{""}}
|
||||
%label(for="new-reason") << Ban Reason
|
||||
%textarea(id="new-reason" name="new") << {{""}}
|
||||
|
||||
%label(for="note") << Admin Note
|
||||
%textarea(id="note" name="note") << {{""}}
|
||||
%label(for="new-note") << Admin Note
|
||||
%textarea(id="new-note" name="note") << {{""}}
|
||||
|
||||
%input(type="submit" value="Ban Domain")
|
||||
%input(type="button" value="Ban Domain" onclick="ban();")
|
||||
|
||||
.data-table.section
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.domain << Instance
|
||||
%td << Date
|
||||
%td.remove
|
||||
%fieldset.section
|
||||
%legend << Domain Bans
|
||||
|
||||
%tbody
|
||||
-for ban in bans
|
||||
.data-table
|
||||
%table#table
|
||||
%thead
|
||||
%tr
|
||||
%td.domain
|
||||
%details
|
||||
%summary -> =ban.domain
|
||||
%form(action="/admin/domain_bans" method="POST")
|
||||
%td.domain << Domain
|
||||
%td << Date
|
||||
%td.remove
|
||||
|
||||
%tbody
|
||||
-for ban in bans
|
||||
%tr(id="{{ban.domain}}")
|
||||
%td.domain
|
||||
%details
|
||||
%summary -> =ban.domain
|
||||
|
||||
.grid-2col
|
||||
.reason << Reason
|
||||
%textarea.reason(id="reason" name="reason") << {{ban.reason or ""}}
|
||||
%textarea.reason(id="{{ban.domain}}-reason" name="reason") << {{ban.reason or ""}}
|
||||
|
||||
.note << Note
|
||||
%textarea.note(id="note" name="note") << {{ban.note or ""}}
|
||||
%textarea.note(id="{{ban.domain}}-note" name="note") << {{ban.note or ""}}
|
||||
|
||||
%input(type="hidden" name="domain" value="{{ban.domain}}")
|
||||
%input(type="submit" value="Update")
|
||||
%input(type="button" value="Update" onclick="update_ban('{{ban.domain}}')")
|
||||
|
||||
%td.date
|
||||
=ban.created.strftime("%Y-%m-%d")
|
||||
%td.date
|
||||
=ban.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.remove
|
||||
%a(href="/admin/domain_bans/delete/{{ban.domain}}" title="Unban domain") << ✖
|
||||
%td.remove
|
||||
%a(href="#", onclick="unban('{{ban.domain}}')" title="Unban domain") << ✖
|
||||
|
|
|
@ -20,56 +20,59 @@
|
|||
%input(type="submit" value="Add Instance")
|
||||
|
||||
-if requests
|
||||
.data-table.section
|
||||
.title << Requests
|
||||
%fieldset.section
|
||||
%legend << Follow Requests
|
||||
.data-table
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.instance << Instance
|
||||
%td.software << Software
|
||||
%td.date << Joined
|
||||
%td.approve
|
||||
%td.deny
|
||||
|
||||
%tbody
|
||||
-for request in requests
|
||||
%tr
|
||||
%td.instance
|
||||
%a(href="https://{{request.domain}}" target="_new") -> =request.domain
|
||||
|
||||
%td.software
|
||||
=request.software or "n/a"
|
||||
|
||||
%td.date
|
||||
=request.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.approve
|
||||
%a(href="/admin/instances/approve/{{request.domain}}" title="Approve Request") << ✓
|
||||
|
||||
%td.deny
|
||||
%a(href="/admin/instances/deny/{{request.domain}}" title="Deny Request") << ✖
|
||||
|
||||
%fieldset.section
|
||||
%legend << Instances
|
||||
|
||||
.data-table
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.instance << Instance
|
||||
%td.software << Software
|
||||
%td.date << Joined
|
||||
%td.approve
|
||||
%td.deny
|
||||
%td.remove
|
||||
|
||||
%tbody
|
||||
-for request in requests
|
||||
-for instance in instances
|
||||
%tr
|
||||
%td.instance
|
||||
%a(href="https://{{request.domain}}" target="_new") -> =request.domain
|
||||
%a(href="https://{{instance.domain}}/" target="_new") -> =instance.domain
|
||||
|
||||
%td.software
|
||||
=request.software or "n/a"
|
||||
=instance.software or "n/a"
|
||||
|
||||
%td.date
|
||||
=request.created.strftime("%Y-%m-%d")
|
||||
=instance.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.approve
|
||||
%a(href="/admin/instances/approve/{{request.domain}}" title="Approve Request") << ✓
|
||||
|
||||
%td.deny
|
||||
%a(href="/admin/instances/deny/{{request.domain}}" title="Deny Request") << ✖
|
||||
|
||||
.data-table.section
|
||||
.title << Instances
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.instance << Instance
|
||||
%td.software << Software
|
||||
%td.date << Joined
|
||||
%td.remove
|
||||
|
||||
%tbody
|
||||
-for instance in instances
|
||||
%tr
|
||||
%td.instance
|
||||
%a(href="https://{{instance.domain}}/" target="_new") -> =instance.domain
|
||||
|
||||
%td.software
|
||||
=instance.software or "n/a"
|
||||
|
||||
%td.date
|
||||
=instance.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.remove
|
||||
%a(href="/admin/instances/delete/{{instance.domain}}" title="Remove Instance") << ✖
|
||||
%td.remove
|
||||
%a(href="/admin/instances/delete/{{instance.domain}}" title="Remove Instance") << ✖
|
||||
|
|
|
@ -16,33 +16,36 @@
|
|||
|
||||
%input(type="submit" value="Ban Software")
|
||||
|
||||
.data-table.section
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.name << Instance
|
||||
%td << Date
|
||||
%td.remove
|
||||
%fieldset.section
|
||||
%legend << Software Bans
|
||||
|
||||
%tbody
|
||||
-for ban in bans
|
||||
.data-table
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.name
|
||||
%details
|
||||
%summary -> =ban.name
|
||||
%form(action="/admin/software_bans" method="POST")
|
||||
.grid-2col
|
||||
.reason << Reason
|
||||
%textarea.reason(id="reason" name="reason") << {{ban.reason or ""}}
|
||||
|
||||
.note << Note
|
||||
%textarea.note(id="note" name="note") << {{ban.note or ""}}
|
||||
|
||||
%input(type="hidden" name="name" value="{{ban.name}}")
|
||||
%input(type="submit" value="Update")
|
||||
|
||||
%td.date
|
||||
=ban.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.name << Name
|
||||
%td << Date
|
||||
%td.remove
|
||||
%a(href="/admin/software_bans/delete/{{ban.name}}" title="Unban software") << ✖
|
||||
|
||||
%tbody
|
||||
-for ban in bans
|
||||
%tr
|
||||
%td.name
|
||||
%details
|
||||
%summary -> =ban.name
|
||||
%form(action="/admin/software_bans" method="POST")
|
||||
.grid-2col
|
||||
.reason << Reason
|
||||
%textarea.reason(id="reason" name="reason") << {{ban.reason or ""}}
|
||||
|
||||
.note << Note
|
||||
%textarea.note(id="note" name="note") << {{ban.note or ""}}
|
||||
|
||||
%input(type="hidden" name="name" value="{{ban.name}}")
|
||||
%input(type="submit" value="Update")
|
||||
|
||||
%td.date
|
||||
=ban.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.remove
|
||||
%a(href="/admin/software_bans/delete/{{ban.name}}" title="Unban software") << ✖
|
||||
|
|
|
@ -19,26 +19,29 @@
|
|||
|
||||
%input(type="submit" value="Add User")
|
||||
|
||||
.data-table.section
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.username << Username
|
||||
%td.handle << Handle
|
||||
%td.date << Joined
|
||||
%td.remove
|
||||
%fieldset.section
|
||||
%legend << Users
|
||||
|
||||
%tbody
|
||||
-for user in users
|
||||
.data-table
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.username
|
||||
=user.username
|
||||
|
||||
%td.handle
|
||||
=user.handle or "n/a"
|
||||
|
||||
%td.date
|
||||
=user.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.username << Username
|
||||
%td.handle << Handle
|
||||
%td.date << Joined
|
||||
%td.remove
|
||||
%a(href="/admin/users/delete/{{user.username}}" title="Remove User") << ✖
|
||||
|
||||
%tbody
|
||||
-for user in users
|
||||
%tr
|
||||
%td.username
|
||||
=user.username
|
||||
|
||||
%td.handle
|
||||
=user.handle or "n/a"
|
||||
|
||||
%td.date
|
||||
=user.created.strftime("%Y-%m-%d")
|
||||
|
||||
%td.remove
|
||||
%a(href="/admin/users/delete/{{user.username}}" title="Remove User") << ✖
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
|
||||
%input(type="submit" value="Add Domain")
|
||||
|
||||
.data-table.section
|
||||
%fieldset.data-table.section
|
||||
%legend << Whitelist
|
||||
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
|
|
|
@ -14,27 +14,34 @@
|
|||
%a(href="https://{{domain}}/actor") << https://{{domain}}/actor</a>
|
||||
|
||||
-if config.approval_required
|
||||
%p.section.message
|
||||
%fieldset.section.message
|
||||
%legend << Require Approval
|
||||
|
||||
Follow requests require approval. You will need to wait for an admin to accept or deny
|
||||
your request.
|
||||
|
||||
-elif config.whitelist_enabled
|
||||
%p.section.message
|
||||
%fieldset.section.message
|
||||
%legend << Whitelist Enabled
|
||||
|
||||
The whitelist is enabled on this instance. Ask the admin to add your instance before
|
||||
joining.
|
||||
|
||||
.data-table.section
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.instance << Instance
|
||||
%td.date << Joined
|
||||
%fieldset.section
|
||||
%legend << Instances
|
||||
|
||||
%tbody
|
||||
-for instance in instances
|
||||
.data-table
|
||||
%table
|
||||
%thead
|
||||
%tr
|
||||
%td.instance -> %a(href="https://{{instance.domain}}/" target="_new")
|
||||
=instance.domain
|
||||
%td.instance << Instance
|
||||
%td.date << Joined
|
||||
|
||||
%td.date
|
||||
=instance.created.strftime("%Y-%m-%d")
|
||||
%tbody
|
||||
-for instance in instances
|
||||
%tr
|
||||
%td.instance -> %a(href="https://{{instance.domain}}/" target="_new")
|
||||
=instance.domain
|
||||
|
||||
%td.date
|
||||
=instance.created.strftime("%Y-%m-%d")
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
-extends "base.haml"
|
||||
-set page="Login"
|
||||
-block content
|
||||
%form.section(action="/login" method="POST")
|
||||
.grid-2col
|
||||
%label(for="username") << Username
|
||||
%input(id="username" name="username" placeholder="Username" value="{{username or ''}}")
|
||||
%fieldset.section
|
||||
%legend << Login
|
||||
|
||||
%label(for="password") << Password
|
||||
%input(id="password" name="password" placeholder="Password" type="password")
|
||||
%form(action="/login" method="POST")
|
||||
.grid-2col
|
||||
%label(for="username") << Username
|
||||
%input(id="username" name="username" placeholder="Username" value="{{username or ''}}")
|
||||
|
||||
%input(type="submit" value="Login")
|
||||
%label(for="password") << Password
|
||||
%input(id="password" name="password" placeholder="Password" type="password")
|
||||
|
||||
%input(type="submit" value="Login")
|
||||
|
|
90
relay/frontend/static/api.js
Normal file
90
relay/frontend/static/api.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
function get_cookie(name) {
|
||||
const regex = new RegExp(`(^| )` + name + `=([^;]+)`);
|
||||
const match = document.cookie.match(regex);
|
||||
|
||||
if (match) {
|
||||
return match[2]
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
function get_date_string(date) {
|
||||
var year = date.getFullYear().toString();
|
||||
var month = date.getMonth().toString();
|
||||
var day = date.getDay().toString();
|
||||
|
||||
if (month.length === 1) {
|
||||
month = "0" + month;
|
||||
}
|
||||
|
||||
if (day.length === 1) {
|
||||
day = "0" + day
|
||||
}
|
||||
|
||||
return `${year}-${month}-${day}`;
|
||||
}
|
||||
|
||||
|
||||
class Client {
|
||||
constructor() {
|
||||
this.token = get_cookie("user-token");
|
||||
}
|
||||
|
||||
|
||||
async request(method, path, body = null) {
|
||||
var headers = {
|
||||
"Accept": "application/json"
|
||||
}
|
||||
|
||||
if (body !== null) {
|
||||
headers["Content-Type"] = "application/json"
|
||||
body = JSON.stringify(body)
|
||||
}
|
||||
|
||||
if (this.token !== null) {
|
||||
headers["Authorization"] = "Bearer " + this.token;
|
||||
}
|
||||
|
||||
const response = await fetch("/api/" + path, {
|
||||
method: method,
|
||||
mode: "cors",
|
||||
cache: "no-store",
|
||||
redirect: "follow",
|
||||
body: body,
|
||||
headers: headers
|
||||
});
|
||||
|
||||
const message = await response.json();
|
||||
|
||||
if (Object.hasOwn(message, "error")) {
|
||||
throw new Error(message.error);
|
||||
}
|
||||
|
||||
if (Object.hasOwn(message, "created")) {
|
||||
message.created = new Date(message.created);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
async ban(domain, reason, note) {
|
||||
const params = {
|
||||
"domain": domain,
|
||||
"reason": reason,
|
||||
"note": note
|
||||
}
|
||||
|
||||
return await this.request("POST", "v1/domain_ban", params);
|
||||
}
|
||||
|
||||
|
||||
async unban(domain) {
|
||||
const params = {"domain": domain}
|
||||
return await this.request("DELETE", "v1/domain_ban", params);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client = new Client();
|
85
relay/frontend/static/domain_ban.js
Normal file
85
relay/frontend/static/domain_ban.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
function create_ban_object(domain, reason, note) {
|
||||
var text = '<details>\n';
|
||||
text += `<summary>${domain}</summary>\n`;
|
||||
text += '<div class="grid-2col">\n';
|
||||
text += `<label for="${domain}-reason" class="reason">Reason</label>\n`;
|
||||
text += `<textarea id="${domain}-reason" class="reason" name="reason">${reason}</textarea>\n`;
|
||||
text += `<label for="${domain}-note" class="note">Note</label>\n`;
|
||||
text += `<textarea id="${domain}-note" class="note" name="note">${note}</textarea>\n`;
|
||||
text += `<input type="button" value="Update" onclick="update_ban(\"${domain}\"")">`;
|
||||
text += '</details>';
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
|
||||
async function ban() {
|
||||
var table = document.getElementById("table");
|
||||
var row = table.insertRow(-1);
|
||||
|
||||
var elems = {
|
||||
domain: document.getElementById("new-domain"),
|
||||
reason: document.getElementById("new-reason"),
|
||||
note: document.getElementById("new-note")
|
||||
}
|
||||
|
||||
var values = {
|
||||
domain: elems.domain.value.trim(),
|
||||
reason: elems.reason.value,
|
||||
note: elems.note.value
|
||||
}
|
||||
|
||||
if (values.domain === "") {
|
||||
alert("Domain is required");
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var ban = await client.ban(values.domain, values.reason, values.note);
|
||||
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
return
|
||||
}
|
||||
|
||||
row.id = ban.domain;
|
||||
var new_domain = row.insertCell(0);
|
||||
var new_date = row.insertCell(1);
|
||||
var new_remove = row.insertCell(2);
|
||||
|
||||
new_domain.className = "domain";
|
||||
new_date.className = "date";
|
||||
new_remove.className = "remove";
|
||||
|
||||
new_domain.innerHTML = create_ban_object(ban.domain, ban.reason, ban.note);
|
||||
new_date.innerHTML = get_date_string(ban.created);
|
||||
new_remove.innerHTML = `<a href="#" onclick="unban('${ban.domain}')" title="Unban domain">✖</a>`;
|
||||
|
||||
elems.domain.value = null;
|
||||
elems.reason.value = null;
|
||||
elems.note.value = null;
|
||||
|
||||
document.querySelectorAll("details.section").forEach((elem) => {
|
||||
elem.open = false;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
async function update_ban(domain) {
|
||||
var row = document.getElementById(domain);
|
||||
}
|
||||
|
||||
|
||||
async function unban(domain) {
|
||||
console.log(domain);
|
||||
|
||||
try {
|
||||
await client.unban(domain);
|
||||
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById(domain).remove();
|
||||
}
|
21
relay/frontend/static/menu.js
Normal file
21
relay/frontend/static/menu.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
const body = document.getElementById("container")
|
||||
const menu = document.getElementById("menu");
|
||||
const menu_open = document.getElementById("menu-open");
|
||||
const menu_close = document.getElementById("menu-close");
|
||||
|
||||
menu_open.addEventListener("click", (event) => {
|
||||
var new_value = menu.attributes.visible.nodeValue === "true" ? "false" : "true";
|
||||
menu.attributes.visible.nodeValue = new_value;
|
||||
});
|
||||
|
||||
menu_close.addEventListener("click", (event) => {
|
||||
menu.attributes.visible.nodeValue = "false"
|
||||
});
|
||||
|
||||
body.addEventListener("click", (event) => {
|
||||
if (event.target === menu_open) {
|
||||
return;
|
||||
}
|
||||
|
||||
menu.attributes.visible.nodeValue = "false";
|
||||
});
|
|
@ -23,17 +23,27 @@ details summary {
|
|||
cursor: pointer;
|
||||
}
|
||||
|
||||
fieldset {
|
||||
margin-left: 0px;
|
||||
margin-right: 0px;
|
||||
}
|
||||
|
||||
fieldset > *:nth-child(2) {
|
||||
margin-top: 0px !important;
|
||||
}
|
||||
|
||||
form input[type="submit"] {
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
legend {
|
||||
background-color: var(--section-background);
|
||||
background-color: var(--table-background);
|
||||
padding: 5px;
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 5px;
|
||||
font-size: 10pt;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
p {
|
|
@ -274,54 +274,6 @@ class DomainBan(View):
|
|||
return Response.new(bans, ctype = 'json')
|
||||
|
||||
|
||||
async def post(self, request: Request) -> Response:
|
||||
data = await self.get_api_data(['domain'], ['note', 'reason'])
|
||||
|
||||
if isinstance(data, Response):
|
||||
return data
|
||||
|
||||
with self.database.session() as conn:
|
||||
if conn.get_domain_ban(data['domain']):
|
||||
return Response.new_error(400, 'Domain already banned', 'json')
|
||||
|
||||
ban = conn.put_domain_ban(**data)
|
||||
|
||||
return Response.new(ban, ctype = 'json')
|
||||
|
||||
|
||||
async def patch(self, request: Request) -> Response:
|
||||
with self.database.session() as conn:
|
||||
data = await self.get_api_data(['domain'], ['note', 'reason'])
|
||||
|
||||
if isinstance(data, Response):
|
||||
return data
|
||||
|
||||
if not conn.get_domain_ban(data['domain']):
|
||||
return Response.new_error(404, 'Domain not banned', 'json')
|
||||
|
||||
if not any([data.get('note'), data.get('reason')]):
|
||||
return Response.new_error(400, 'Must include note and/or reason parameters', 'json')
|
||||
|
||||
ban = conn.update_domain_ban(data['domain'], **data)
|
||||
|
||||
return Response.new(ban, ctype = 'json')
|
||||
|
||||
|
||||
async def delete(self, request: Request) -> Response:
|
||||
with self.database.session() as conn:
|
||||
data = await self.get_api_data(['domain'], [])
|
||||
|
||||
if isinstance(data, Response):
|
||||
return data
|
||||
|
||||
if not conn.get_domain_ban(data['domain']):
|
||||
return Response.new_error(404, 'Domain not banned', 'json')
|
||||
|
||||
conn.del_domain_ban(data['domain'])
|
||||
|
||||
return Response.new({'message': 'Unbanned domain'}, ctype = 'json')
|
||||
|
||||
|
||||
@register_route('/api/v1/software_ban')
|
||||
class SoftwareBan(View):
|
||||
async def get(self, request: Request) -> Response:
|
||||
|
|
|
@ -2,9 +2,11 @@ from __future__ import annotations
|
|||
|
||||
import typing
|
||||
|
||||
from Crypto.Random import get_random_bytes
|
||||
from aiohttp.abc import AbstractView
|
||||
from aiohttp.hdrs import METH_ALL as METHODS
|
||||
from aiohttp.web import HTTPMethodNotAllowed
|
||||
from base64 import b64encode
|
||||
from functools import cached_property
|
||||
from json.decoder import JSONDecodeError
|
||||
|
||||
|
@ -56,6 +58,7 @@ class View(AbstractView):
|
|||
|
||||
|
||||
async def _run_handler(self, handler: Callable[..., Any], **kwargs: Any) -> Response:
|
||||
self.request['hash'] = b64encode(get_random_bytes(16)).decode('ascii')
|
||||
return await handler(self.request, **self.request.match_info, **kwargs)
|
||||
|
||||
|
||||
|
|
|
@ -26,21 +26,31 @@ UNAUTH_ROUTES = {
|
|||
|
||||
@web.middleware
|
||||
async def handle_frontend_path(request: web.Request, handler: Callable) -> Response:
|
||||
app = get_app()
|
||||
|
||||
if request.path in UNAUTH_ROUTES or request.path.startswith('/admin'):
|
||||
request['token'] = request.cookies.get('user-token')
|
||||
request['user'] = None
|
||||
|
||||
if request['token']:
|
||||
with get_app().database.session(False) as conn:
|
||||
with app.database.session(False) as conn:
|
||||
request['user'] = conn.get_user_by_token(request['token'])
|
||||
|
||||
if request['user'] and request.path == '/login':
|
||||
return Response.new('', 302, {'Location': '/'})
|
||||
|
||||
if not request['user'] and request.path.startswith('/admin'):
|
||||
return Response.new('', 302, {'Location': f'/login?redir={request.path}'})
|
||||
response = Response.new('', 302, {'Location': f'/login?redir={request.path}'})
|
||||
response.del_cookie('user-token')
|
||||
return response
|
||||
|
||||
return await handler(request)
|
||||
response = await handler(request)
|
||||
|
||||
if not request['user'] and request['token']:
|
||||
print("del token")
|
||||
response.del_cookie('user-token')
|
||||
|
||||
return response
|
||||
|
||||
|
||||
@register_route('/')
|
||||
|
@ -96,8 +106,8 @@ class Login(View):
|
|||
domain = self.config.domain,
|
||||
path = '/',
|
||||
secure = True,
|
||||
httponly = True,
|
||||
samesite = 'Strict'
|
||||
httponly = False,
|
||||
samesite = 'lax'
|
||||
)
|
||||
|
||||
return resp
|
||||
|
@ -271,7 +281,7 @@ class AdminWhitelist(View):
|
|||
|
||||
with self.database.session(True) as conn:
|
||||
if conn.get_domain_whitelist(data['domain']):
|
||||
return await self.get(request, message = "Domain already in whitelist")
|
||||
return await self.get(request, error = "Domain already in whitelist")
|
||||
|
||||
conn.put_domain_whitelist(data['domain'])
|
||||
|
||||
|
@ -284,7 +294,7 @@ class AdminWhitlistDelete(View):
|
|||
with self.database.session() as conn:
|
||||
if not conn.get_domain_whitelist(domain):
|
||||
msg = 'Whitelisted domain not found'
|
||||
return await AdminWhitelist.run("GET", request, message = msg)
|
||||
return await AdminWhitelist.run("GET", request, error = msg)
|
||||
|
||||
conn.del_domain_whitelist(domain)
|
||||
|
||||
|
@ -342,7 +352,7 @@ class AdminDomainBansDelete(View):
|
|||
async def get(self, request: Request, domain: str) -> Response:
|
||||
with self.database.session() as conn:
|
||||
if not conn.get_domain_ban(domain):
|
||||
return await AdminDomainBans.run("GET", request, message = 'Domain ban not found')
|
||||
return await AdminDomainBans.run("GET", request, error = 'Domain ban not found')
|
||||
|
||||
conn.del_domain_ban(domain)
|
||||
|
||||
|
@ -400,7 +410,7 @@ class AdminSoftwareBansDelete(View):
|
|||
async def get(self, request: Request, name: str) -> Response:
|
||||
with self.database.session() as conn:
|
||||
if not conn.get_software_ban(name):
|
||||
return await AdminSoftwareBans.run("GET", request, message = 'Software ban not found')
|
||||
return await AdminSoftwareBans.run("GET", request, error = 'Software ban not found')
|
||||
|
||||
conn.del_software_ban(name)
|
||||
|
||||
|
@ -441,7 +451,7 @@ class AdminUsers(View):
|
|||
|
||||
with self.database.session(True) as conn:
|
||||
if conn.get_user(data['username']):
|
||||
return await self.get(request, message = "User already exists")
|
||||
return await self.get(request, error = "User already exists")
|
||||
|
||||
conn.put_user(data['username'], data['password'], data['handle'])
|
||||
|
||||
|
@ -453,7 +463,7 @@ class AdminUsersDelete(View):
|
|||
async def get(self, request: Request, name: str) -> Response:
|
||||
with self.database.session() as conn:
|
||||
if not conn.get_user(name):
|
||||
return await AdminUsers.run("GET", request, message = 'User not found')
|
||||
return await AdminUsers.run("GET", request, error = 'User not found')
|
||||
|
||||
conn.del_user(name)
|
||||
|
||||
|
|
Loading…
Reference in a new issue