mirror of
https://git.pleroma.social/pleroma/relay.git
synced 2024-11-23 15:08:00 +00:00
Compare commits
10 commits
10ba039938
...
b068f4f91e
Author | SHA1 | Date | |
---|---|---|---|
b068f4f91e | |||
0f3b72830b | |||
50c323ba1e | |||
1ffc609058 | |||
08f4f0e72d | |||
31f5decc4a | |||
ad17fb64f1 | |||
f775335e80 | |||
aeb84d7a72 | |||
17690268bc |
|
@ -140,25 +140,6 @@ class Application(web.Application):
|
||||||
|
|
||||||
return '; '.join(data) + ';'
|
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:
|
def push_message(self, inbox: str, message: Message, instance: Row) -> None:
|
||||||
self['push_queue'].put((inbox, message, instance))
|
self['push_queue'].put((inbox, message, instance))
|
||||||
|
@ -305,6 +286,7 @@ async def handle_response_headers(request: web.Request, handler: Callable) -> Re
|
||||||
resp = await handler(request)
|
resp = await handler(request)
|
||||||
resp.headers['Server'] = 'ActivityRelay'
|
resp.headers['Server'] = 'ActivityRelay'
|
||||||
|
|
||||||
|
# Still have to figure out how csp headers work
|
||||||
# if resp.content_type == 'text/html':
|
# if resp.content_type == 'text/html':
|
||||||
# resp.headers['Content-Security-Policy'] = Application.DEFAULT.get_csp(request)
|
# resp.headers['Content-Security-Policy'] = Application.DEFAULT.get_csp(request)
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,10 @@ schemes:
|
||||||
- https
|
- https
|
||||||
|
|
||||||
securityDefinitions:
|
securityDefinitions:
|
||||||
|
Cookie:
|
||||||
|
type: apiKey
|
||||||
|
in: cookie
|
||||||
|
name: user-token
|
||||||
Bearer:
|
Bearer:
|
||||||
type: apiKey
|
type: apiKey
|
||||||
name: Authorization
|
name: Authorization
|
||||||
|
@ -549,6 +553,104 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: "#/definitions/Error"
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
/v1/user:
|
||||||
|
get:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Get a list of all local users
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: List of users
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
|
||||||
|
post:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Create a new user
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: formData
|
||||||
|
name: password
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
- in: formData
|
||||||
|
name: handle
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Newly created user
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
"404":
|
||||||
|
description: User already exists
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
patch:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Update a user's password or handle
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
- in: formData
|
||||||
|
name: password
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: password
|
||||||
|
- in: formData
|
||||||
|
name: handle
|
||||||
|
required: false
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"200":
|
||||||
|
description: Updated user data
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/User"
|
||||||
|
"404":
|
||||||
|
description: User does not exist
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
|
delete:
|
||||||
|
tags:
|
||||||
|
- User
|
||||||
|
description: Delete a user
|
||||||
|
parameters:
|
||||||
|
- in: formData
|
||||||
|
name: username
|
||||||
|
required: true
|
||||||
|
type: string
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
responses:
|
||||||
|
"202":
|
||||||
|
description: Successfully deleted user
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Message"
|
||||||
|
"404":
|
||||||
|
description: User not found
|
||||||
|
schema:
|
||||||
|
$ref: "#/definitions/Error"
|
||||||
|
|
||||||
/v1/whitelist:
|
/v1/whitelist:
|
||||||
get:
|
get:
|
||||||
tags:
|
tags:
|
||||||
|
@ -748,6 +850,21 @@ definitions:
|
||||||
description: Character string used for authenticating with the api
|
description: Character string used for authenticating with the api
|
||||||
type: string
|
type: string
|
||||||
|
|
||||||
|
User:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
username:
|
||||||
|
description: Username of the account
|
||||||
|
type: string
|
||||||
|
handle:
|
||||||
|
description: Fediverse handle associated with the account
|
||||||
|
type: string
|
||||||
|
format: email
|
||||||
|
created:
|
||||||
|
description: Date the account was created
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
|
||||||
Whitelist:
|
Whitelist:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
|
|
@ -190,7 +190,22 @@ class Connection(SqlConnection):
|
||||||
return cur.one() # type: ignore
|
return cur.one() # type: ignore
|
||||||
|
|
||||||
|
|
||||||
def put_user(self, username: str, password: str, handle: str | None = None) -> Row:
|
def put_user(self, username: str, password: str | None, handle: str | None = None) -> Row:
|
||||||
|
if self.get_user(username):
|
||||||
|
data = {
|
||||||
|
'username': username
|
||||||
|
}
|
||||||
|
|
||||||
|
if password:
|
||||||
|
data['password'] = password
|
||||||
|
|
||||||
|
if handle:
|
||||||
|
data['handler'] = handle
|
||||||
|
|
||||||
|
else:
|
||||||
|
if password is None:
|
||||||
|
raise ValueError('Password cannot be empty')
|
||||||
|
|
||||||
data = {
|
data = {
|
||||||
'username': username,
|
'username': username,
|
||||||
'hash': self.hasher.hash(password),
|
'hash': self.hasher.hash(password),
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Config"
|
-set page="Config"
|
||||||
|
|
||||||
|
-block head
|
||||||
|
%script(type="application/javascript" src="/static/config.js" nonce="{{view.request['hash']}}" defer)
|
||||||
|
|
||||||
-import "functions.haml" as func
|
-import "functions.haml" as func
|
||||||
-block content
|
-block content
|
||||||
%fieldset.section
|
%fieldset.section
|
||||||
%legend << Config
|
%legend << Config
|
||||||
%form(action="/admin/config" method="POST")
|
|
||||||
.grid-2col
|
.grid-2col
|
||||||
%label(for="name") << Name
|
%label(for="name") << Name
|
||||||
%input(id = "name" name="name" placeholder="Relay Name" value="{{config.name or ''}}")
|
%input(id = "name" name="name" placeholder="Relay Name" value="{{config.name or ''}}")
|
||||||
|
@ -23,5 +27,3 @@
|
||||||
|
|
||||||
%label(for="approval-required") << Approval Required
|
%label(for="approval-required") << Approval Required
|
||||||
=func.new_checkbox("approval-required", config.approval_required)
|
=func.new_checkbox("approval-required", config.approval_required)
|
||||||
|
|
||||||
%input(type="submit" value="Save")
|
|
||||||
|
|
|
@ -2,20 +2,20 @@
|
||||||
-set page="Domain Bans"
|
-set page="Domain Bans"
|
||||||
|
|
||||||
-block head
|
-block head
|
||||||
%script(type="application/javascript" src="/static/domain_ban.js" nonce="{{view.request['hash']}}", defer)
|
%script(type="application/javascript" src="/static/domain_ban.js" nonce="{{view.request['hash']}}")
|
||||||
|
|
||||||
-block content
|
-block content
|
||||||
%details.section
|
%details.section
|
||||||
%summary << Ban Domain
|
%summary << Ban Domain
|
||||||
#add-item
|
#add-item
|
||||||
%label(for="new-domain") << Domain
|
%label(for="new-domain") << Domain
|
||||||
%input(type="domain" id="new-domain" name="domain" placeholder="Domain")
|
%input(type="domain" id="new-domain" placeholder="Domain")
|
||||||
|
|
||||||
%label(for="new-reason") << Ban Reason
|
%label(for="new-reason") << Ban Reason
|
||||||
%textarea(id="new-reason" name="new") << {{""}}
|
%textarea(id="new-reason") << {{""}}
|
||||||
|
|
||||||
%label(for="new-note") << Admin Note
|
%label(for="new-note") << Admin Note
|
||||||
%textarea(id="new-note" name="note") << {{""}}
|
%textarea(id="new-note") << {{""}}
|
||||||
|
|
||||||
%input(type="button" value="Ban Domain" onclick="ban();")
|
%input(type="button" value="Ban Domain" onclick="ban();")
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@
|
||||||
%legend << Domain Bans
|
%legend << Domain Bans
|
||||||
|
|
||||||
.data-table
|
.data-table
|
||||||
%table#table
|
%table
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%td.domain << Domain
|
%td.domain << Domain
|
||||||
|
@ -38,11 +38,11 @@
|
||||||
%summary -> =ban.domain
|
%summary -> =ban.domain
|
||||||
|
|
||||||
.grid-2col
|
.grid-2col
|
||||||
.reason << Reason
|
%label.reason(for="{{ban.domain}}-reason") << Reason
|
||||||
%textarea.reason(id="{{ban.domain}}-reason" name="reason") << {{ban.reason or ""}}
|
%textarea.reason(id="{{ban.domain}}-reason") << {{ban.reason or ""}}
|
||||||
|
|
||||||
.note << Note
|
%label.note(for="{{ban.domain}}-note") << Note
|
||||||
%textarea.note(id="{{ban.domain}}-note" name="note") << {{ban.note or ""}}
|
%textarea.note(id="{{ban.domain}}-note") << {{ban.note or ""}}
|
||||||
|
|
||||||
%input(type="button" value="Update" onclick="update_ban('{{ban.domain}}')")
|
%input(type="button" value="Update" onclick="update_ban('{{ban.domain}}')")
|
||||||
|
|
||||||
|
@ -50,4 +50,4 @@
|
||||||
=ban.created.strftime("%Y-%m-%d")
|
=ban.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.remove
|
%td.remove
|
||||||
%a(href="#", onclick="unban('{{ban.domain}}')" title="Unban domain") << ✖
|
%a(href="#" onclick="unban('{{ban.domain}}')" title="Unban domain") << ✖
|
||||||
|
|
|
@ -1,29 +1,32 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Instances"
|
-set page="Instances"
|
||||||
|
|
||||||
|
-block head
|
||||||
|
%script(type="application/javascript" src="/static/instance.js" nonce="{{view.request['hash']}}")
|
||||||
|
|
||||||
-block content
|
-block content
|
||||||
%details.section
|
%details.section
|
||||||
%summary << Add Instance
|
%summary << Add Instance
|
||||||
%form(action="/admin/instances" method="POST")
|
|
||||||
#add-item
|
#add-item
|
||||||
%label(for="domain") << Domain
|
%label(for="new-actor") << Actor
|
||||||
%input(type="domain" id="domain" name="domain" placeholder="Domain")
|
%input(type="url" id="new-actor" placeholder="Actor URL")
|
||||||
|
|
||||||
%label(for="actor") << Actor URL
|
%label(for="new-inbox") << Inbox
|
||||||
%input(type="url" id="actor" name="actor" placeholder="Actor URL")
|
%input(type="url" id="new-inbox" placeholder="Inbox URL")
|
||||||
|
|
||||||
%label(for="inbox") << Inbox URL
|
%label(for="new-followid") << Follow ID
|
||||||
%input(type="url" id="inbox" name="inbox" placeholder="Inbox URL")
|
%input(type="url" id="new-followid" placeholder="Follow ID URL")
|
||||||
|
|
||||||
%label(for="software") << Software
|
%label(for="new-software") << Software
|
||||||
%input(name="software" id="software" placeholder="software")
|
%input(id="new-software" placeholder="software")
|
||||||
|
|
||||||
%input(type="submit" value="Add Instance")
|
%input(type="button" value="Add Instance", onclick="add_instance()")
|
||||||
|
|
||||||
-if requests
|
-if requests
|
||||||
%fieldset.section
|
%fieldset.section.requests
|
||||||
%legend << Follow Requests
|
%legend << Follow Requests
|
||||||
.data-table
|
.data-table
|
||||||
%table
|
%table#requests
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%td.instance << Instance
|
%td.instance << Instance
|
||||||
|
@ -34,7 +37,7 @@
|
||||||
|
|
||||||
%tbody
|
%tbody
|
||||||
-for request in requests
|
-for request in requests
|
||||||
%tr
|
%tr(id="{{request.domain}}")
|
||||||
%td.instance
|
%td.instance
|
||||||
%a(href="https://{{request.domain}}" target="_new") -> =request.domain
|
%a(href="https://{{request.domain}}" target="_new") -> =request.domain
|
||||||
|
|
||||||
|
@ -45,16 +48,16 @@
|
||||||
=request.created.strftime("%Y-%m-%d")
|
=request.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.approve
|
%td.approve
|
||||||
%a(href="/admin/instances/approve/{{request.domain}}" title="Approve Request") << ✓
|
%a(href="#" onclick="req_response('{{request.domain}}', true)" title="Approve Request") << ✓
|
||||||
|
|
||||||
%td.deny
|
%td.deny
|
||||||
%a(href="/admin/instances/deny/{{request.domain}}" title="Deny Request") << ✖
|
%a(href="#" onclick="req_response('{{request.domain}}', false)" title="Deny Request") << ✖
|
||||||
|
|
||||||
%fieldset.section
|
%fieldset.section.instances
|
||||||
%legend << Instances
|
%legend << Instances
|
||||||
|
|
||||||
.data-table
|
.data-table
|
||||||
%table
|
%table#instances
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%td.instance << Instance
|
%td.instance << Instance
|
||||||
|
@ -64,7 +67,7 @@
|
||||||
|
|
||||||
%tbody
|
%tbody
|
||||||
-for instance in instances
|
-for instance in instances
|
||||||
%tr
|
%tr(id="{{instance.domain}}")
|
||||||
%td.instance
|
%td.instance
|
||||||
%a(href="https://{{instance.domain}}/" target="_new") -> =instance.domain
|
%a(href="https://{{instance.domain}}/" target="_new") -> =instance.domain
|
||||||
|
|
||||||
|
@ -75,4 +78,4 @@
|
||||||
=instance.created.strftime("%Y-%m-%d")
|
=instance.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.remove
|
%td.remove
|
||||||
%a(href="/admin/instances/delete/{{instance.domain}}" title="Remove Instance") << ✖
|
%a(href="#" onclick="del_instance('{{instance.domain}}')" title="Remove Instance") << ✖
|
||||||
|
|
|
@ -1,20 +1,23 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Software Bans"
|
-set page="Software Bans"
|
||||||
|
|
||||||
|
-block head
|
||||||
|
%script(type="application/javascript" src="/static/software_ban.js" nonce="{{view.request['hash']}}")
|
||||||
|
|
||||||
-block content
|
-block content
|
||||||
%details.section
|
%details.section
|
||||||
%summary << Ban Software
|
%summary << Ban Software
|
||||||
%form(action="/admin/software_bans" method="POST")
|
|
||||||
#add-item
|
#add-item
|
||||||
%label(for="name") << Name
|
%label(for="new-name") << Domain
|
||||||
%input(id="name" name="name" placeholder="Name")
|
%input(type="name" id="new-name" placeholder="Domain")
|
||||||
|
|
||||||
%label(for="reason") << Ban Reason
|
%label(for="new-reason") << Ban Reason
|
||||||
%textarea(id="reason" name="reason") << {{""}}
|
%textarea(id="new-reason") << {{""}}
|
||||||
|
|
||||||
%label(for="note") << Admin Note
|
%label(for="new-note") << Admin Note
|
||||||
%textarea(id="note" name="note") << {{""}}
|
%textarea(id="new-note") << {{""}}
|
||||||
|
|
||||||
%input(type="submit" value="Ban Software")
|
%input(type="submit" value="Ban Software" onclick="ban()")
|
||||||
|
|
||||||
%fieldset.section
|
%fieldset.section
|
||||||
%legend << Software Bans
|
%legend << Software Bans
|
||||||
|
@ -29,23 +32,22 @@
|
||||||
|
|
||||||
%tbody
|
%tbody
|
||||||
-for ban in bans
|
-for ban in bans
|
||||||
%tr
|
%tr(id="{{ban.name}}")
|
||||||
%td.name
|
%td.name
|
||||||
%details
|
%details
|
||||||
%summary -> =ban.name
|
%summary -> =ban.name
|
||||||
%form(action="/admin/software_bans" method="POST")
|
|
||||||
.grid-2col
|
.grid-2col
|
||||||
.reason << Reason
|
%label.reason(for="{{ban.name}}-reason") << Reason
|
||||||
%textarea.reason(id="reason" name="reason") << {{ban.reason or ""}}
|
%textarea.reason(id="{{ban.name}}-reason") << {{ban.reason or ""}}
|
||||||
|
|
||||||
.note << Note
|
%label.note(for="{{ban.name}}-note") << Note
|
||||||
%textarea.note(id="note" name="note") << {{ban.note or ""}}
|
%textarea.note(id="{{ban.name}}-note") << {{ban.note or ""}}
|
||||||
|
|
||||||
%input(type="hidden" name="name" value="{{ban.name}}")
|
%input(type="button" value="Update" onclick="update_ban('{{ban.name}}')")
|
||||||
%input(type="submit" value="Update")
|
|
||||||
|
|
||||||
%td.date
|
%td.date
|
||||||
=ban.created.strftime("%Y-%m-%d")
|
=ban.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.remove
|
%td.remove
|
||||||
%a(href="/admin/software_bans/delete/{{ban.name}}" title="Unban software") << ✖
|
%a(href="#" onclick="unban('{{ban.name}}')" title="Unban name") << ✖
|
||||||
|
|
|
@ -1,29 +1,32 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Users"
|
-set page="Users"
|
||||||
|
|
||||||
|
-block head
|
||||||
|
%script(type="application/javascript" src="/static/user.js" nonce="{{view.request['hash']}}")
|
||||||
|
|
||||||
-block content
|
-block content
|
||||||
%details.section
|
%details.section
|
||||||
%summary << Add User
|
%summary << Add User
|
||||||
%form(action="/admin/users", method="POST")
|
|
||||||
#add-item
|
#add-item
|
||||||
%label(for="username") << Username
|
%label(for="new-username") << Username
|
||||||
%input(id="username" name="username" placeholder="Username")
|
%input(id="new-username" name="username" placeholder="Username")
|
||||||
|
|
||||||
%label(for="password") << Password
|
%label(for="new-password") << Password
|
||||||
%input(type="password" id="password" name="password" placeholder="Password")
|
%input(id="new-password" type="password" placeholder="Password")
|
||||||
|
|
||||||
%label(for="password2") << Password Again
|
%label(for="new-password2") << Password Again
|
||||||
%input(type="password" id="password2" name="password2" placeholder="Password Again")
|
%input(id="new-password2" type="password" placeholder="Password Again")
|
||||||
|
|
||||||
%label(for="handle") << Handle
|
%label(for="new-handle") << Handle
|
||||||
%input(type="email" name="handle" id="handle" placeholder="handle")
|
%input(id="new-handle" type="email" placeholder="handle")
|
||||||
|
|
||||||
%input(type="submit" value="Add User")
|
%input(type="button" value="Add User" onclick="add_user()")
|
||||||
|
|
||||||
%fieldset.section
|
%fieldset.section
|
||||||
%legend << Users
|
%legend << Users
|
||||||
|
|
||||||
.data-table
|
.data-table
|
||||||
%table
|
%table#users
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%td.username << Username
|
%td.username << Username
|
||||||
|
@ -33,7 +36,7 @@
|
||||||
|
|
||||||
%tbody
|
%tbody
|
||||||
-for user in users
|
-for user in users
|
||||||
%tr
|
%tr(id="{{user.username}}")
|
||||||
%td.username
|
%td.username
|
||||||
=user.username
|
=user.username
|
||||||
|
|
||||||
|
@ -44,4 +47,4 @@
|
||||||
=user.created.strftime("%Y-%m-%d")
|
=user.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.remove
|
%td.remove
|
||||||
%a(href="/admin/users/delete/{{user.username}}" title="Remove User") << ✖
|
%a(href="#" onclick="del_user('{{user.username}}')" title="Remove User") << ✖
|
||||||
|
|
|
@ -1,19 +1,22 @@
|
||||||
-extends "base.haml"
|
-extends "base.haml"
|
||||||
-set page="Whitelist"
|
-set page="Whitelist"
|
||||||
|
|
||||||
|
-block head
|
||||||
|
%script(type="application/javascript" src="/static/whitelist.js" nonce="{{view.request['hash']}}")
|
||||||
|
|
||||||
-block content
|
-block content
|
||||||
%details.section
|
%details.section
|
||||||
%summary << Add Domain
|
%summary << Add Domain
|
||||||
%form(action="/admin/whitelist" method="POST")
|
|
||||||
#add-item
|
#add-item
|
||||||
%label(for="domain") << Domain
|
%label(for="new-domain") << Domain
|
||||||
%input(type="domain" id="domain" name="domain" placeholder="Domain")
|
%input(type="domain" id="new-domain" placeholder="Domain")
|
||||||
|
|
||||||
%input(type="submit" value="Add Domain")
|
%input(type="button" value="Add Domain", onclick="add_whitelist()")
|
||||||
|
|
||||||
%fieldset.data-table.section
|
%fieldset.data-table.section
|
||||||
%legend << Whitelist
|
%legend << Whitelist
|
||||||
|
|
||||||
%table
|
%table#whitelist
|
||||||
%thead
|
%thead
|
||||||
%tr
|
%tr
|
||||||
%td.domain << Domain
|
%td.domain << Domain
|
||||||
|
@ -22,7 +25,7 @@
|
||||||
|
|
||||||
%tbody
|
%tbody
|
||||||
-for item in whitelist
|
-for item in whitelist
|
||||||
%tr
|
%tr(id="{{item.domain}}")
|
||||||
%td.domain
|
%td.domain
|
||||||
=item.domain
|
=item.domain
|
||||||
|
|
||||||
|
@ -30,4 +33,4 @@
|
||||||
=item.created.strftime("%Y-%m-%d")
|
=item.created.strftime("%Y-%m-%d")
|
||||||
|
|
||||||
%td.remove
|
%td.remove
|
||||||
%a(href="/admin/whitelist/delete/{{item.domain}}" title="Remove whitlisted domain") << ✖
|
%a(href="#" onclick="del_whitelist('{{item.domain}}')" title="Remove whitlisted domain") << ✖
|
||||||
|
|
|
@ -1,15 +1,3 @@
|
||||||
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) {
|
function get_date_string(date) {
|
||||||
var year = date.getFullYear().toString();
|
var year = date.getFullYear().toString();
|
||||||
var month = date.getMonth().toString();
|
var month = date.getMonth().toString();
|
||||||
|
@ -27,13 +15,25 @@ function get_date_string(date) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Client {
|
function append_table_row(table, row_name, row) {
|
||||||
constructor() {
|
var table_row = table.insertRow(-1);
|
||||||
this.token = get_cookie("user-token");
|
table_row.id = row_name;
|
||||||
|
|
||||||
|
index = 0;
|
||||||
|
|
||||||
|
for (var prop in row) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(row, prop)) {
|
||||||
|
var cell = table_row.insertCell(index);
|
||||||
|
cell.className = prop;
|
||||||
|
cell.innerHTML = row[prop];
|
||||||
|
|
||||||
|
index += 1;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async request(method, path, body = null) {
|
async function request(method, path, body = null) {
|
||||||
var headers = {
|
var headers = {
|
||||||
"Accept": "application/json"
|
"Accept": "application/json"
|
||||||
}
|
}
|
||||||
|
@ -43,10 +43,6 @@ class Client {
|
||||||
body = JSON.stringify(body)
|
body = JSON.stringify(body)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.token !== null) {
|
|
||||||
headers["Authorization"] = "Bearer " + this.token;
|
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch("/api/" + path, {
|
const response = await fetch("/api/" + path, {
|
||||||
method: method,
|
method: method,
|
||||||
mode: "cors",
|
mode: "cors",
|
||||||
|
@ -62,29 +58,18 @@ class Client {
|
||||||
throw new Error(message.error);
|
throw new Error(message.error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (Array.isArray(message)) {
|
||||||
|
message.forEach((msg) => {
|
||||||
|
if (Object.hasOwn(msg, "created")) {
|
||||||
|
msg.created = new Date(msg.created);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
} else {
|
||||||
if (Object.hasOwn(message, "created")) {
|
if (Object.hasOwn(message, "created")) {
|
||||||
message.created = new Date(message.created);
|
message.created = new Date(message.created);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return message;
|
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();
|
|
||||||
|
|
34
relay/frontend/static/config.js
Normal file
34
relay/frontend/static/config.js
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
const elems = [
|
||||||
|
document.querySelector("#name"),
|
||||||
|
document.querySelector("#description"),
|
||||||
|
document.querySelector("#theme"),
|
||||||
|
document.querySelector("#log-level"),
|
||||||
|
document.querySelector("#whitelist-enabled"),
|
||||||
|
document.querySelector("#approval-required")
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
async function handle_config_change(event) {
|
||||||
|
params = {
|
||||||
|
key: event.target.id,
|
||||||
|
value: event.target.type === "checkbox" ? event.target.checked : event.target.value
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await request("POST", "v1/config", params);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.key === "name") {
|
||||||
|
document.querySelector("#header .title").innerHTML = params.value;
|
||||||
|
document.querySelector("title").innerHTML = params.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
for (const elem of elems) {
|
||||||
|
elem.addEventListener("change", handle_config_change);
|
||||||
|
}
|
|
@ -3,9 +3,9 @@ function create_ban_object(domain, reason, note) {
|
||||||
text += `<summary>${domain}</summary>\n`;
|
text += `<summary>${domain}</summary>\n`;
|
||||||
text += '<div class="grid-2col">\n';
|
text += '<div class="grid-2col">\n';
|
||||||
text += `<label for="${domain}-reason" class="reason">Reason</label>\n`;
|
text += `<label for="${domain}-reason" class="reason">Reason</label>\n`;
|
||||||
text += `<textarea id="${domain}-reason" class="reason" name="reason">${reason}</textarea>\n`;
|
text += `<textarea id="${domain}-reason" class="reason">${reason}</textarea>\n`;
|
||||||
text += `<label for="${domain}-note" class="note">Note</label>\n`;
|
text += `<label for="${domain}-note" class="note">Note</label>\n`;
|
||||||
text += `<textarea id="${domain}-note" class="note" name="note">${note}</textarea>\n`;
|
text += `<textarea id="${domain}-note" class="note">${note}</textarea>\n`;
|
||||||
text += `<input type="button" value="Update" onclick="update_ban(\"${domain}\"")">`;
|
text += `<input type="button" value="Update" onclick="update_ban(\"${domain}\"")">`;
|
||||||
text += '</details>';
|
text += '</details>';
|
||||||
|
|
||||||
|
@ -14,9 +14,7 @@ function create_ban_object(domain, reason, note) {
|
||||||
|
|
||||||
|
|
||||||
async function ban() {
|
async function ban() {
|
||||||
var table = document.getElementById("table");
|
var table = document.querySelector("table");
|
||||||
var row = table.insertRow(-1);
|
|
||||||
|
|
||||||
var elems = {
|
var elems = {
|
||||||
domain: document.getElementById("new-domain"),
|
domain: document.getElementById("new-domain"),
|
||||||
reason: document.getElementById("new-reason"),
|
reason: document.getElementById("new-reason"),
|
||||||
|
@ -35,49 +33,59 @@ async function ban() {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var ban = await client.ban(values.domain, values.reason, values.note);
|
var ban = await request("POST", "v1/domain_ban", values);
|
||||||
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
alert(err);
|
alert(err);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
row.id = ban.domain;
|
append_table_row(document.getElementById("instances"), ban.domain, {
|
||||||
var new_domain = row.insertCell(0);
|
domain: create_ban_object(ban.domain, ban.reason, ban.note),
|
||||||
var new_date = row.insertCell(1);
|
date: get_date_string(ban.created),
|
||||||
var new_remove = row.insertCell(2);
|
remove: `<a href="#" onclick="unban('${ban.domain}')" title="Unban domain">✖</a>`
|
||||||
|
});
|
||||||
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.domain.value = null;
|
||||||
elems.reason.value = null;
|
elems.reason.value = null;
|
||||||
elems.note.value = null;
|
elems.note.value = null;
|
||||||
|
|
||||||
document.querySelectorAll("details.section").forEach((elem) => {
|
document.querySelector("details.section").open = false;
|
||||||
elem.open = false;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function update_ban(domain) {
|
async function update_ban(domain) {
|
||||||
var row = document.getElementById(domain);
|
var row = document.getElementById(domain);
|
||||||
|
|
||||||
|
var elems = {
|
||||||
|
"reason": row.querySelector("textarea.reason"),
|
||||||
|
"note": row.querySelector("textarea.note")
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
"domain": domain,
|
||||||
|
"reason": elems.reason.value,
|
||||||
|
"note": elems.note.value
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await request("PATCH", "v1/domain_ban", values)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
row.querySelector("details").open = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async function unban(domain) {
|
async function unban(domain) {
|
||||||
console.log(domain);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await client.unban(domain);
|
await request("DELETE", "v1/domain_ban", {"domain": domain});
|
||||||
|
|
||||||
} catch (err) {
|
} catch (error) {
|
||||||
alert(err);
|
alert(error);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
93
relay/frontend/static/instance.js
Normal file
93
relay/frontend/static/instance.js
Normal file
|
@ -0,0 +1,93 @@
|
||||||
|
async function add_instance() {
|
||||||
|
var elems = {
|
||||||
|
actor: document.getElementById("new-actor"),
|
||||||
|
inbox: document.getElementById("new-inbox"),
|
||||||
|
followid: document.getElementById("new-followid"),
|
||||||
|
software: document.getElementById("new-software")
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
actor: elems.actor.value.trim(),
|
||||||
|
inbox: elems.inbox.value.trim(),
|
||||||
|
followid: elems.followid.value.trim(),
|
||||||
|
software: elems.software.value.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.actor === "") {
|
||||||
|
alert("Actor is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var instance = await request("POST", "v1/instance", values);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert(err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append_table_row(document.getElementById("instances"), instance.domain, {
|
||||||
|
domain: `<a href="https://${instance.domain}/" target="_new">${instance.domain}</a>`,
|
||||||
|
software: instance.software,
|
||||||
|
date: get_date_string(instance.created),
|
||||||
|
remove: `<a href="#" onclick="del_instance('${instance.domain}')" title="Remove Instance">✖</a>`
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.actor.value = null;
|
||||||
|
elems.inbox.value = null;
|
||||||
|
elems.followid.value = null;
|
||||||
|
elems.software.value = null;
|
||||||
|
|
||||||
|
document.querySelector("details.section").open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function del_instance(domain) {
|
||||||
|
try {
|
||||||
|
await request("DELETE", "v1/instance", {"domain": domain});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(domain).remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function req_response(domain, accept) {
|
||||||
|
params = {
|
||||||
|
"domain": domain,
|
||||||
|
"accept": accept
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await request("POST", "v1/request", params);
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(domain).remove();
|
||||||
|
|
||||||
|
if (document.getElementById("requests").rows.length < 2) {
|
||||||
|
document.querySelector("fieldset.requests").remove()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!accept) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
instances = await request("GET", `v1/instance`, null);
|
||||||
|
instances.forEach((instance) => {
|
||||||
|
if (instance.domain === domain) {
|
||||||
|
append_table_row(document.getElementById("instances"), instance.domain, {
|
||||||
|
domain: `<a href="https://${instance.domain}/" target="_new">${instance.domain}</a>`,
|
||||||
|
software: instance.software,
|
||||||
|
date: get_date_string(instance.created),
|
||||||
|
remove: `<a href="#" onclick="del_instance('${instance.domain}')" title="Remove Instance">✖</a>`
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
95
relay/frontend/static/software_ban.js
Normal file
95
relay/frontend/static/software_ban.js
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
function create_ban_object(name, reason, note) {
|
||||||
|
var text = '<details>\n';
|
||||||
|
text += `<summary>${name}</summary>\n`;
|
||||||
|
text += '<div class="grid-2col">\n';
|
||||||
|
text += `<label for="${name}-reason" class="reason">Reason</label>\n`;
|
||||||
|
text += `<textarea id="${name}-reason" class="reason">${reason}</textarea>\n`;
|
||||||
|
text += `<label for="${name}-note" class="note">Note</label>\n`;
|
||||||
|
text += `<textarea id="${name}-note" class="note">${note}</textarea>\n`;
|
||||||
|
text += `<input type="button" value="Update" onclick="update_ban(\"${name}\"")">`;
|
||||||
|
text += '</details>';
|
||||||
|
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function ban() {
|
||||||
|
var table = document.querySelector("table");
|
||||||
|
var row = table.insertRow(-1);
|
||||||
|
|
||||||
|
var elems = {
|
||||||
|
name: document.getElementById("new-name"),
|
||||||
|
reason: document.getElementById("new-reason"),
|
||||||
|
note: document.getElementById("new-note")
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
name: elems.name.value.trim(),
|
||||||
|
reason: elems.reason.value,
|
||||||
|
note: elems.note.value
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.name === "") {
|
||||||
|
alert("Domain is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var ban = await request("POST", "v1/software_ban", values);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert(err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append_table_row(document.getElementById("instances"), ban.name, {
|
||||||
|
name: create_ban_object(ban.name, ban.reason, ban.note),
|
||||||
|
date: get_date_string(ban.created),
|
||||||
|
remove: `<a href="#" onclick="unban('${ban.domain}')" title="Unban software">✖</a>`
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.name.value = null;
|
||||||
|
elems.reason.value = null;
|
||||||
|
elems.note.value = null;
|
||||||
|
|
||||||
|
document.querySelector("details.section").open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function update_ban(name) {
|
||||||
|
var row = document.getElementById(name);
|
||||||
|
|
||||||
|
var elems = {
|
||||||
|
"reason": row.querySelector("textarea.reason"),
|
||||||
|
"note": row.querySelector("textarea.note")
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
"name": name,
|
||||||
|
"reason": elems.reason.value,
|
||||||
|
"note": elems.note.value
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await request("PATCH", "v1/software_ban", values)
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
row.querySelector("details").open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function unban(name) {
|
||||||
|
try {
|
||||||
|
await request("DELETE", "v1/software_ban", {"name": name});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(name).remove();
|
||||||
|
}
|
60
relay/frontend/static/user.js
Normal file
60
relay/frontend/static/user.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
async function add_user() {
|
||||||
|
var elems = {
|
||||||
|
username: document.getElementById("new-username"),
|
||||||
|
password: document.getElementById("new-password"),
|
||||||
|
password2: document.getElementById("new-password2"),
|
||||||
|
handle: document.getElementById("new-handle")
|
||||||
|
}
|
||||||
|
|
||||||
|
var values = {
|
||||||
|
username: elems.username.value.trim(),
|
||||||
|
password: elems.password.value.trim(),
|
||||||
|
password2: elems.password2.value.trim(),
|
||||||
|
handle: elems.handle.value.trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.username === "" | values.password === "" | values.password2 === "") {
|
||||||
|
alert("Username, password, and password2 are required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (values.password !== values.password2) {
|
||||||
|
alert("Passwords do not match");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var user = await request("POST", "v1/user", values);
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert(err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append_table_row(document.getElementById("users"), user.username, {
|
||||||
|
domain: user.username,
|
||||||
|
handle: user.handle,
|
||||||
|
date: get_date_string(user.created),
|
||||||
|
remove: `<a href="#" onclick="del_user('${user.username}')" title="Delete User">✖</a>`
|
||||||
|
});
|
||||||
|
|
||||||
|
elems.username.value = null;
|
||||||
|
elems.password.value = null;
|
||||||
|
elems.password2.value = null;
|
||||||
|
elems.handle.value = null;
|
||||||
|
|
||||||
|
document.querySelector("details.section").open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function del_user(username) {
|
||||||
|
try {
|
||||||
|
await request("DELETE", "v1/user", {"username": username});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(username).remove();
|
||||||
|
}
|
39
relay/frontend/static/whitelist.js
Normal file
39
relay/frontend/static/whitelist.js
Normal file
|
@ -0,0 +1,39 @@
|
||||||
|
async function add_whitelist() {
|
||||||
|
var domain_elem = document.getElementById("new-domain");
|
||||||
|
var domain = domain_elem.value.trim();
|
||||||
|
|
||||||
|
if (domain === "") {
|
||||||
|
alert("Domain is required");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var item = await request("POST", "v1/whitelist", {"domain": domain});
|
||||||
|
|
||||||
|
} catch (err) {
|
||||||
|
alert(err);
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
append_table_row(document.getElementById("whitelist"), item.domain, {
|
||||||
|
domain: item.domain,
|
||||||
|
date: get_date_string(item.created),
|
||||||
|
remove: `<a href="#" onclick="del_whitelist('${item.domain}')" title="Remove whitelisted domain">✖</a>`
|
||||||
|
});
|
||||||
|
|
||||||
|
domain_elem.value = null;
|
||||||
|
document.querySelector("details.section").open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function del_whitelist(domain) {
|
||||||
|
try {
|
||||||
|
await request("DELETE", "v1/whitelist", {"domain": domain});
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
alert(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById(domain).remove();
|
||||||
|
}
|
|
@ -10,7 +10,7 @@ from .base import View, register_route
|
||||||
|
|
||||||
from .. import __version__
|
from .. import __version__
|
||||||
from ..database import ConfigData
|
from ..database import ConfigData
|
||||||
from ..misc import Message, Response, get_app
|
from ..misc import Message, Response, boolean, get_app
|
||||||
|
|
||||||
if typing.TYPE_CHECKING:
|
if typing.TYPE_CHECKING:
|
||||||
from aiohttp.web import Request
|
from aiohttp.web import Request
|
||||||
|
@ -34,6 +34,10 @@ def check_api_path(method: str, path: str) -> bool:
|
||||||
@web.middleware
|
@web.middleware
|
||||||
async def handle_api_path(request: Request, handler: Callable) -> Response:
|
async def handle_api_path(request: Request, handler: Callable) -> Response:
|
||||||
try:
|
try:
|
||||||
|
if (token := request.cookies.get('user-token')):
|
||||||
|
request['token'] = token
|
||||||
|
|
||||||
|
else:
|
||||||
request['token'] = request.headers['Authorization'].replace('Bearer', '').strip()
|
request['token'] = request.headers['Authorization'].replace('Bearer', '').strip()
|
||||||
|
|
||||||
with get_app().database.session() as conn:
|
with get_app().database.session() as conn:
|
||||||
|
@ -133,6 +137,8 @@ class Config(View):
|
||||||
if isinstance(data, Response):
|
if isinstance(data, Response):
|
||||||
return data
|
return data
|
||||||
|
|
||||||
|
data['key'] = data['key'].replace('-', '_');
|
||||||
|
|
||||||
if data['key'] not in ConfigData.USER_KEYS():
|
if data['key'] not in ConfigData.USER_KEYS():
|
||||||
return Response.new_error(400, 'Invalid key', 'json')
|
return Response.new_error(400, 'Invalid key', 'json')
|
||||||
|
|
||||||
|
@ -161,7 +167,7 @@ class Config(View):
|
||||||
class Inbox(View):
|
class Inbox(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
with self.database.session() as conn:
|
with self.database.session() as conn:
|
||||||
data = tuple(conn.execute('SELECT * FROM inboxes').all())
|
data = conn.get_inboxes()
|
||||||
|
|
||||||
return Response.new(data, ctype = 'json')
|
return Response.new(data, ctype = 'json')
|
||||||
|
|
||||||
|
@ -186,6 +192,12 @@ class Inbox(View):
|
||||||
|
|
||||||
data['inbox'] = actor_data.shared_inbox
|
data['inbox'] = actor_data.shared_inbox
|
||||||
|
|
||||||
|
if not data.get('software'):
|
||||||
|
nodeinfo = await self.client.fetch_nodeinfo(data['domain'])
|
||||||
|
|
||||||
|
if nodeinfo is not None:
|
||||||
|
data['software'] = nodeinfo.sw_name
|
||||||
|
|
||||||
row = conn.put_inbox(**data)
|
row = conn.put_inbox(**data)
|
||||||
|
|
||||||
return Response.new(row, ctype = 'json')
|
return Response.new(row, ctype = 'json')
|
||||||
|
@ -206,7 +218,7 @@ class Inbox(View):
|
||||||
return Response.new(instance, ctype = 'json')
|
return Response.new(instance, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
async def delete(self, request: Request, domain: str) -> Response:
|
async def delete(self, request: Request) -> Response:
|
||||||
with self.database.session() as conn:
|
with self.database.session() as conn:
|
||||||
data = await self.get_api_data(['domain'], [])
|
data = await self.get_api_data(['domain'], [])
|
||||||
|
|
||||||
|
@ -232,10 +244,7 @@ class RequestView(View):
|
||||||
|
|
||||||
async def post(self, request: Request) -> Response:
|
async def post(self, request: Request) -> Response:
|
||||||
data = await self.get_api_data(['domain', 'accept'], [])
|
data = await self.get_api_data(['domain', 'accept'], [])
|
||||||
|
data['accept'] = boolean(data['accept'])
|
||||||
if not isinstance(data['accept'], bool):
|
|
||||||
atype = type(data['accept']).__name__
|
|
||||||
return Response.new_error(400, f'Invalid type for "accept": {atype}', 'json')
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
with self.database.session(True) as conn:
|
with self.database.session(True) as conn:
|
||||||
|
@ -274,6 +283,54 @@ class DomainBan(View):
|
||||||
return Response.new(bans, ctype = 'json')
|
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)
|
||||||
|
|
||||||
|
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')
|
@register_route('/api/v1/software_ban')
|
||||||
class SoftwareBan(View):
|
class SoftwareBan(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
|
@ -311,7 +368,7 @@ class SoftwareBan(View):
|
||||||
if not any([data.get('note'), data.get('reason')]):
|
if not any([data.get('note'), data.get('reason')]):
|
||||||
return Response.new_error(400, 'Must include note and/or reason parameters', 'json')
|
return Response.new_error(400, 'Must include note and/or reason parameters', 'json')
|
||||||
|
|
||||||
ban = conn.update_software_ban(data['name'], **data)
|
ban = conn.update_software_ban(**data)
|
||||||
|
|
||||||
return Response.new(ban, ctype = 'json')
|
return Response.new(ban, ctype = 'json')
|
||||||
|
|
||||||
|
@ -331,6 +388,63 @@ class SoftwareBan(View):
|
||||||
return Response.new({'message': 'Unbanned software'}, ctype = 'json')
|
return Response.new({'message': 'Unbanned software'}, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
@register_route('/api/v1/user')
|
||||||
|
class User(View):
|
||||||
|
async def get(self, request: Request) -> Response:
|
||||||
|
with self.database.session() as conn:
|
||||||
|
items = []
|
||||||
|
|
||||||
|
for row in conn.execute('SELECT * FROM users'):
|
||||||
|
del row['hash']
|
||||||
|
items.append(row)
|
||||||
|
|
||||||
|
return Response.new(items, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def post(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username', 'password'], ['handle'])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session() as conn:
|
||||||
|
if conn.get_user(data['username']):
|
||||||
|
return Response.new_error(404, 'User already exists', 'json')
|
||||||
|
|
||||||
|
user = conn.put_user(**data)
|
||||||
|
del user['hash']
|
||||||
|
|
||||||
|
return Response.new(user, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def patch(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username'], ['password', ['handle']])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session(True) as conn:
|
||||||
|
user = conn.put_user(**data)
|
||||||
|
del user['hash']
|
||||||
|
|
||||||
|
return Response.new(user, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
|
async def delete(self, request: Request) -> Response:
|
||||||
|
data = await self.get_api_data(['username'], [])
|
||||||
|
|
||||||
|
if isinstance(data, Response):
|
||||||
|
return data
|
||||||
|
|
||||||
|
with self.database.session(True) as conn:
|
||||||
|
if not conn.get_user(data['username']):
|
||||||
|
return Response.new_error(404, 'User does not exist', 'json')
|
||||||
|
|
||||||
|
conn.del_user(data['username'])
|
||||||
|
|
||||||
|
return Response.new({'message': 'Deleted user'}, ctype = 'json')
|
||||||
|
|
||||||
|
|
||||||
@register_route('/api/v1/whitelist')
|
@register_route('/api/v1/whitelist')
|
||||||
class Whitelist(View):
|
class Whitelist(View):
|
||||||
async def get(self, request: Request) -> Response:
|
async def get(self, request: Request) -> Response:
|
||||||
|
|
|
@ -126,7 +126,7 @@ class View(AbstractView):
|
||||||
return Response.new_error(400, 'Invalid JSON data', 'json')
|
return Response.new_error(400, 'Invalid JSON data', 'json')
|
||||||
|
|
||||||
else:
|
else:
|
||||||
post_data = convert_data(await self.request.query) # type: ignore
|
post_data = convert_data(self.request.query) # type: ignore
|
||||||
|
|
||||||
data = {}
|
data = {}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue