stop using pusher
parent
83cda67c43
commit
c6f74f5296
4
env
4
env
|
@ -12,8 +12,8 @@ export DISCORD_BOT_TOKEN="blahblahblah"
|
|||
export TURNSTILE_SITEKEY="blahblahblah"
|
||||
export TURNSTILE_SECRET="blahblahblah"
|
||||
export YOUTUBE_KEY="blahblahblah"
|
||||
export PUSHER_ID="blahblahblah"
|
||||
export PUSHER_KEY="blahblahblah"
|
||||
export VAPID_PUBLIC_KEY="blahblahblah"
|
||||
export VAPID_PRIVATE_KEY="blahblahblah"
|
||||
export IMGUR_KEY="blahblahblah"
|
||||
export SPAM_SIMILARITY_THRESHOLD="0.5"
|
||||
export SPAM_URL_SIMILARITY_THRESHOLD="0.1"
|
||||
|
|
|
@ -0,0 +1,70 @@
|
|||
'use strict';
|
||||
|
||||
function urlB64ToUint8Array(base64String) {
|
||||
const padding = '='.repeat((4 - base64String.length % 4) % 4);
|
||||
const base64 = (base64String + padding)
|
||||
.replace(/\-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const rawData = window.atob(base64);
|
||||
const outputArray = new Uint8Array(rawData.length);
|
||||
|
||||
for (let i = 0; i < rawData.length; ++i) {
|
||||
outputArray[i] = rawData.charCodeAt(i);
|
||||
}
|
||||
return outputArray;
|
||||
}
|
||||
|
||||
function updateSubscriptionOnServer(subscription, apiEndpoint) {
|
||||
var formData = new FormData();
|
||||
formData.append("subscription_json", JSON.stringify(subscription));
|
||||
|
||||
const xhr = createXhrWithFormKey(
|
||||
apiEndpoint,
|
||||
'POST',
|
||||
formData
|
||||
);
|
||||
|
||||
xhr[0].send(xhr[1]);
|
||||
}
|
||||
|
||||
function subscribeUser(swRegistration, applicationServerPublicKey, apiEndpoint) {
|
||||
const applicationServerKey = urlB64ToUint8Array(applicationServerPublicKey);
|
||||
swRegistration.pushManager.subscribe({
|
||||
userVisibleOnly: true,
|
||||
applicationServerKey: applicationServerKey
|
||||
})
|
||||
.then(function(subscription) {
|
||||
return updateSubscriptionOnServer(subscription, apiEndpoint);
|
||||
|
||||
})
|
||||
.then(function(response) {
|
||||
if (!response.ok) {
|
||||
throw new Error('Bad status code from server.');
|
||||
}
|
||||
return response.json();
|
||||
})
|
||||
.then(function(responseData) {
|
||||
if (responseData.status!=="success") {
|
||||
throw new Error('Bad response from server.');
|
||||
}
|
||||
})
|
||||
.catch(function() {
|
||||
});
|
||||
}
|
||||
|
||||
function registerServiceWorker(serviceWorkerUrl, applicationServerPublicKey, apiEndpoint){
|
||||
let swRegistration = null;
|
||||
if ('serviceWorker' in navigator && 'PushManager' in window) {
|
||||
navigator.serviceWorker.register(serviceWorkerUrl)
|
||||
.then(function(swReg) {
|
||||
subscribeUser(swReg, applicationServerPublicKey, apiEndpoint);
|
||||
|
||||
swRegistration = swReg;
|
||||
})
|
||||
.catch(function() {
|
||||
});
|
||||
} else {
|
||||
}
|
||||
return swRegistration;
|
||||
}
|
|
@ -1,12 +1,9 @@
|
|||
importScripts("https://js.pusher.com/beams/service-worker.js");
|
||||
|
||||
// offline static page handler
|
||||
// @crgd
|
||||
'use strict';
|
||||
|
||||
const CACHE_NAME = "offlineCache-v1";
|
||||
const OFFLINE_URL = "/assets/offline.html";
|
||||
|
||||
self.addEventListener("install", (event) => {
|
||||
self.addEventListener("install", () => {
|
||||
const cacheOfflinePage = async () => {
|
||||
const cache = await caches.open(CACHE_NAME);
|
||||
await cache.add(new Request(OFFLINE_URL, {cache: "reload"}));
|
||||
|
@ -41,11 +38,39 @@ self.addEventListener("fetch", (event) => {
|
|||
const networkResponse = await fetch(event.request);
|
||||
return networkResponse;
|
||||
} catch (error) {
|
||||
console.log("Fetch failed; returning offline page instead.", error);
|
||||
|
||||
const cachedResponse = await caches.match(OFFLINE_URL);
|
||||
return cachedResponse;
|
||||
}
|
||||
})());
|
||||
}
|
||||
});
|
||||
|
||||
self.addEventListener('push', function(event) {
|
||||
const pushData = event.data.text();
|
||||
let data, title, body, url, icon;
|
||||
try {
|
||||
data = JSON.parse(pushData);
|
||||
title = data.title;
|
||||
body = data.body;
|
||||
url = data.url;
|
||||
icon = data.icon;
|
||||
} catch(e) {
|
||||
title = "Untitled";
|
||||
body = pushData;
|
||||
}
|
||||
const options = {
|
||||
body: body,
|
||||
data: {url: url},
|
||||
icon: icon
|
||||
};
|
||||
|
||||
event.waitUntil(
|
||||
self.registration.showNotification(title, options)
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('notificationclick', (e) => {
|
||||
if (e.notification.data.url)
|
||||
e.waitUntil(clients.openWindow(e.notification.data.url));
|
||||
e.notification.close();
|
||||
});
|
File diff suppressed because one or more lines are too long
|
@ -35,3 +35,4 @@ from .sub_logs import *
|
|||
from .media import *
|
||||
if FEATURES['STREAMERS']:
|
||||
from .streamers import *
|
||||
from .push_subscriptions import *
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
import time
|
||||
|
||||
from sqlalchemy import Column, ForeignKey
|
||||
from sqlalchemy.sql.sqltypes import *
|
||||
|
||||
from files.classes import Base
|
||||
|
||||
class PushSubscription(Base):
|
||||
__tablename__ = "push_subscriptions"
|
||||
user_id = Column(Integer, ForeignKey("users.id"), primary_key=True)
|
||||
subscription_json = Column(String, primary_key=True)
|
||||
created_utc = Column(Integer)
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
if "created_utc" not in kwargs: kwargs["created_utc"] = int(time.time())
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
return f"<{self.__class__.__name__}(id={self.id})>"
|
|
@ -1,9 +1,8 @@
|
|||
from sys import stdout
|
||||
|
||||
from flask import g
|
||||
from pusher_push_notifications import PushNotifications
|
||||
|
||||
from files.classes import Comment, Notification
|
||||
from files.classes import Comment, Notification, PushSubscription
|
||||
|
||||
from .const import *
|
||||
from .regex import *
|
||||
|
@ -103,35 +102,24 @@ def NOTIFY_USERS(text, v):
|
|||
|
||||
return notify_users - bots
|
||||
|
||||
if PUSHER_ID != DEFAULT_CONFIG_VALUE:
|
||||
beams_client = PushNotifications(instance_id=PUSHER_ID, secret_key=PUSHER_KEY)
|
||||
if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE:
|
||||
from pywebpush import webpush
|
||||
import json
|
||||
|
||||
def pusher_thread(interests, title, notifbody, url):
|
||||
title = censor_slurs(title, None)
|
||||
notifbody = censor_slurs(notifbody, None)
|
||||
if len(notifbody) > PUSHER_LIMIT:
|
||||
notifbody = notifbody[:PUSHER_LIMIT] + "..."
|
||||
claims = {"sub": f"mailto:{EMAIL}"}
|
||||
|
||||
beams_client.publish_to_interests(
|
||||
interests=[interests],
|
||||
publish_body={
|
||||
'web': {
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': notifbody,
|
||||
'deep_link': url,
|
||||
'icon': f'{SITE_FULL}/icon.webp?v=1',
|
||||
}
|
||||
},
|
||||
'fcm': {
|
||||
'notification': {
|
||||
'title': title,
|
||||
'body': notifbody,
|
||||
},
|
||||
'data': {
|
||||
'url': url,
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
stdout.flush()
|
||||
def push_notif(uid, title, body, url):
|
||||
subscriptions = g.db.query(PushSubscription).filter_by(user_id=uid).all()
|
||||
for subscription in subscriptions:
|
||||
try: response = webpush(
|
||||
subscription_info=json.loads(subscription.subscription_json),
|
||||
data=json.dumps({
|
||||
"title": title,
|
||||
"body": body,
|
||||
'url': url,
|
||||
'icon': f'{SITE_FULL}/icon.webp?v=1',
|
||||
}),
|
||||
vapid_private_key=VAPID_PRIVATE_KEY,
|
||||
vapid_claims=claims
|
||||
)
|
||||
except: continue
|
||||
|
|
|
@ -16,8 +16,8 @@ DISCORD_BOT_TOKEN = environ.get("DISCORD_BOT_TOKEN", DEFAULT_CONFIG_VALUE).strip
|
|||
TURNSTILE_SITEKEY = environ.get("TURNSTILE_SITEKEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
TURNSTILE_SECRET = environ.get("TURNSTILE_SECRET", DEFAULT_CONFIG_VALUE).strip()
|
||||
YOUTUBE_KEY = environ.get("YOUTUBE_KEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
PUSHER_ID = environ.get("PUSHER_ID", DEFAULT_CONFIG_VALUE).strip()
|
||||
PUSHER_KEY = environ.get("PUSHER_KEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
VAPID_PUBLIC_KEY = environ.get("VAPID_PUBLIC_KEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
VAPID_PRIVATE_KEY = environ.get("VAPID_PRIVATE_KEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
IMGUR_KEY = environ.get("IMGUR_KEY", DEFAULT_CONFIG_VALUE).strip()
|
||||
SPAM_SIMILARITY_THRESHOLD = float(environ.get("SPAM_SIMILARITY_THRESHOLD", "0.5").strip())
|
||||
SPAM_URL_SIMILARITY_THRESHOLD = float(environ.get("SPAM_URL_SIMILARITY_THRESHOLD", "0.1").strip())
|
||||
|
@ -55,7 +55,7 @@ DEFAULT_RATELIMIT = "3/second;30/minute;200/hour;1000/day"
|
|||
DEFAULT_RATELIMIT_SLOWER = "1/second;30/minute;200/hour;1000/day"
|
||||
DEFAULT_RATELIMIT_USER = DEFAULT_RATELIMIT_SLOWER
|
||||
|
||||
PUSHER_LIMIT = 1000 # API allows 10 KB but better safe than sorry
|
||||
PUSH_NOTIF_LIMIT = 1000 # API allows 10 KB but better safe than sorry
|
||||
|
||||
IS_LOCALHOST = SITE == "localhost" or SITE == "127.0.0.1" or SITE.startswith("192.168.") or SITE.endswith(".local")
|
||||
|
||||
|
|
|
@ -48,3 +48,4 @@ if FEATURES['ASSET_SUBMISSIONS']:
|
|||
if FEATURES['STREAMERS']:
|
||||
from .streamers import *
|
||||
from .special import *
|
||||
from .push_notifs import *
|
||||
|
|
|
@ -313,9 +313,7 @@ def comment(v):
|
|||
n = Notification(comment_id=c.id, user_id=x)
|
||||
g.db.add(n)
|
||||
|
||||
if parent.author.id != v.id and PUSHER_ID != DEFAULT_CONFIG_VALUE and not v.shadowbanned:
|
||||
interests = f'{SITE}{parent.author.id}'
|
||||
|
||||
if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and parent.author.id != v.id and not v.shadowbanned:
|
||||
title = f'New reply by @{c.author_name}'
|
||||
|
||||
if len(c.body) > 500: notifbody = c.body[:500] + '...'
|
||||
|
@ -323,7 +321,7 @@ def comment(v):
|
|||
|
||||
url = f'{SITE_FULL}/comment/{c.id}?context=8&read=true#context'
|
||||
|
||||
gevent.spawn(pusher_thread, interests, title, notifbody, url)
|
||||
push_notif(parent.author.id, title, notifbody, url)
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ def calc_users():
|
|||
@app.context_processor
|
||||
def inject_constants():
|
||||
return {"environ":environ, "SITE":SITE, "SITE_NAME":SITE_NAME, "SITE_FULL":SITE_FULL,
|
||||
"AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "PUSHER_ID":PUSHER_ID,
|
||||
"AUTOJANNY_ID":AUTOJANNY_ID, "MODMAIL_ID":MODMAIL_ID, "VAPID_PUBLIC_KEY":VAPID_PUBLIC_KEY,
|
||||
"CC":CC, "CC_TITLE":CC_TITLE, "listdir":listdir, "os_path":path, "AEVANN_ID":AEVANN_ID,
|
||||
"PIZZASHILL_ID":PIZZASHILL_ID, "DEFAULT_COLOR":DEFAULT_COLOR,
|
||||
"COLORS":COLORS, "time":time, "PERMS":PERMS, "FEATURES":FEATURES,
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
from files.routes.wrappers import *
|
||||
from files.__main__ import app
|
||||
from flask import request, g
|
||||
from files.classes.push_subscriptions import PushSubscription
|
||||
|
||||
@app.post("/push_subscribe")
|
||||
@auth_required
|
||||
def push_subscribe(v):
|
||||
subscription_json = request.values.get("subscription_json")
|
||||
|
||||
subscription = g.db.query(PushSubscription).filter_by(
|
||||
user_id=v.id,
|
||||
subscription_json=subscription_json,
|
||||
).one_or_none()
|
||||
|
||||
if not subscription:
|
||||
subscription = PushSubscription(
|
||||
user_id=v.id,
|
||||
subscription_json=subscription_json,
|
||||
)
|
||||
g.db.add(subscription)
|
||||
|
||||
return ''
|
|
@ -471,9 +471,7 @@ def message2(v, username):
|
|||
g.db.add(notif)
|
||||
|
||||
|
||||
if PUSHER_ID != DEFAULT_CONFIG_VALUE and not v.shadowbanned:
|
||||
interests = f'{SITE}{user.id}'
|
||||
|
||||
if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and not v.shadowbanned:
|
||||
title = f'New message from @{username}'
|
||||
|
||||
if len(message) > 500: notifbody = message[:500] + '...'
|
||||
|
@ -481,7 +479,7 @@ def message2(v, username):
|
|||
|
||||
url = f'{SITE_FULL}/notifications/messages'
|
||||
|
||||
gevent.spawn(pusher_thread, interests, title, notifbody, url)
|
||||
push_notif(user.id, title, notifbody, url)
|
||||
|
||||
return {"message": "Message sent!"}
|
||||
|
||||
|
@ -545,9 +543,7 @@ def messagereply(v):
|
|||
notif = Notification(comment_id=c.id, user_id=user_id)
|
||||
g.db.add(notif)
|
||||
|
||||
if PUSHER_ID != DEFAULT_CONFIG_VALUE and not v.shadowbanned:
|
||||
interests = f'{SITE}{user_id}'
|
||||
|
||||
if VAPID_PUBLIC_KEY != DEFAULT_CONFIG_VALUE and not v.shadowbanned:
|
||||
title = f'New message from @{v.username}'
|
||||
|
||||
if len(body) > 500: notifbody = body[:500] + '...'
|
||||
|
@ -555,7 +551,7 @@ def messagereply(v):
|
|||
|
||||
url = f'{SITE_FULL}/notifications/messages'
|
||||
|
||||
gevent.spawn(pusher_thread, interests, title, notifbody, url)
|
||||
push_notif(user_id, title, notifbody, url)
|
||||
|
||||
top_comment = c.top_comment(g.db)
|
||||
|
||||
|
|
|
@ -167,14 +167,15 @@
|
|||
</nav>
|
||||
{% endif %}
|
||||
|
||||
{% if request.path == '/' and PUSHER_ID != DEFAULT_CONFIG_VALUE and v %}
|
||||
<div class="d-none" id="strid">{{SITE}}{{v.id}}</div>
|
||||
<div class="d-none" id="pusherid">{{PUSHER_ID}}</div>
|
||||
<script defer src="{{'js/vendor/pusher.js' | asset}}"></script>
|
||||
{% if request.path == '/' and v %}
|
||||
<script defer src="/assets/js/register_service_worker.js"></script>
|
||||
<script>
|
||||
if (typeof Android != 'undefined') {
|
||||
Android.Subscribe('{{SITE}}{{v.id}}');
|
||||
}
|
||||
document.addEventListener('DOMContentLoaded', function () {
|
||||
registerServiceWorker(
|
||||
"/assets/js/service_worker.js",
|
||||
"{{VAPID_PUBLIC_KEY}}",
|
||||
"/push_subscribe")
|
||||
});
|
||||
</script>
|
||||
{% endif %}
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@ add_header Referrer-Policy "same-origin";
|
|||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
|
||||
add_header X-Frame-Options "deny";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' challenges.cloudflare.com; connect-src 'self' tls-use1.fpapi.io api.fpjs.io 00bb6d59-7b11-4339-b1ae-b1f1259d1316.pushnotifications.pusher.com; object-src 'none';";
|
||||
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' challenges.cloudflare.com; connect-src 'self' tls-use1.fpapi.io api.fpjs.io; object-src 'none';";
|
||||
|
||||
sendfile on;
|
||||
sendfile_max_chunk 1m;
|
||||
|
|
|
@ -8,7 +8,7 @@ server {
|
|||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
|
||||
add_header X-Frame-Options "deny";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' challenges.cloudflare.com rdrama.net; connect-src 'self' tls-use1.fpapi.io api.fpjs.io 00bb6d59-7b11-4339-b1ae-b1f1259d1316.pushnotifications.pusher.com; object-src 'none';";
|
||||
add_header Content-Security-Policy "script-src 'self' 'unsafe-inline' challenges.cloudflare.com rdrama.net; connect-src 'self' tls-use1.fpapi.io api.fpjs.io; object-src 'none';";
|
||||
|
||||
location / {
|
||||
proxy_pass http://localhost:5000/;
|
||||
|
|
|
@ -19,6 +19,7 @@ matplotlib
|
|||
owoify-py
|
||||
Pillow
|
||||
pyotp
|
||||
pywebpush
|
||||
qrcode
|
||||
redis
|
||||
requests
|
||||
|
@ -27,7 +28,6 @@ tinycss2
|
|||
tldextract
|
||||
user-agents
|
||||
psycopg2-binary
|
||||
pusher_push_notifications
|
||||
youtube-dl
|
||||
yattag
|
||||
webptools
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
. ./env
|
||||
. ./.env
|
||||
export DATABASE_URL="postgresql://postgres@postgres:5432"
|
||||
export REDIS_URL="redis://redis:6379"
|
||||
export PROXY_URL="http://opera-proxy:18080"
|
||||
|
|
|
@ -5,8 +5,8 @@ apt -y install git redis-server python3-pip ffmpeg tmux nginx snapd ufw gpg-agen
|
|||
git config --global credential.helper store
|
||||
cd /rDrama
|
||||
git config branch.frost.rebase true
|
||||
cp ./env /env
|
||||
. /env
|
||||
cp ./env ./.env
|
||||
. ./.env
|
||||
|
||||
mkdir /scripts
|
||||
cp ./startup.sh /scripts/s
|
||||
|
|
Loading…
Reference in New Issue