billing frontend for mariadb. setup as otb_billing for outsidethebox.top accounting. also involved with outsidethedb
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

157 lines
4.8 KiB

from pathlib import Path
from flask import send_file, abort, Blueprint, render_template, session, redirect, url_for, flash
import hmac, hashlib, time, urllib.parse, os
OTB_PORTAL_SHARED_SECRET = os.getenv("OTB_PORTAL_SHARED_SECRET", "!2Eas678")
OTB_CLOUD_URL = os.getenv("OTB_CLOUD_URL", "https://otb-cloud.outsidethebox.top")
portal_services_bp = Blueprint("portal_services", __name__)
def _portal_user_is_logged_in() -> bool:
return bool(
session.get("portal_user_id")
or session.get("client_user_id")
or session.get("portal_client_id")
or session.get("client_id")
or session.get("user_id")
)
@portal_services_bp.route("/portal/services")
def portal_services_home():
if not _portal_user_is_logged_in():
flash("Please sign in to access services.", "warning")
return redirect(url_for("portal_login"))
client = {
"contact_name": session.get("portal_contact_name"),
"company_name": session.get("portal_company_name"),
"email": session.get("portal_email"),
}
client_name = (
client.get("contact_name")
or client.get("company_name")
or client.get("email")
or "Client"
)
services = [
{
"key": "follow_me",
"name": "Follow-me Tracker",
"summary": "Create and manage your GPS tracking network. Free for up to 2 users.",
"status": "beta",
"enabled": True,
"href": "/portal/services/follow-me-launch",
"button_text": "Open Follow-me",
},
{
"key": "video_render",
"name": "Video Rendering / Streaming",
"summary": "Submit video rendering, conversion, and hosted streaming jobs.",
"status": "coming_soon",
"enabled": False,
"href": "#",
"button_text": "Coming Soon",
},
{
"key": "otb_cloud",
"name": "OTB Cloud Backup & Storage",
"summary": "Secure backup and storage for documents, photos, videos, and device uploads.",
"status": "beta",
"enabled": True,
"href": "/portal/services/otb-cloud-launch",
"button_text": "Open OTB Cloud",
},
{
"key": "miner_rentals",
"name": "Miner Rentals",
"summary": "Rent available OTB hashpower by time or package.",
"status": "coming_soon",
"enabled": False,
"href": "#",
"button_text": "Coming Soon",
},
]
return render_template(
"portal/services_here.html",
client=client,
client_name=client_name,
services=services,
)
def build_otb_cloud_handoff_url(uid, email):
ts = str(int(time.time()))
payload = f"{uid}|{email}|{ts}".encode("utf-8")
sig = hmac.new(
OTB_PORTAL_SHARED_SECRET.encode(),
payload,
hashlib.sha256
).hexdigest()
query = urllib.parse.urlencode({
"uid": uid,
"email": email,
"ts": ts,
"sig": sig,
})
return f"{OTB_CLOUD_URL}/auth/handoff?{query}"
@portal_services_bp.route("/portal/services/otb-cloud-launch")
def portal_launch_otb_cloud():
if not _portal_user_is_logged_in():
flash("Please sign in to access services.", "warning")
return redirect(url_for("portal_login"))
uid = session.get("portal_client_id")
email = session.get("portal_email")
if not uid or not email:
flash("Unable to launch OTB Cloud because the portal session is missing required account details.", "danger")
return redirect(url_for("portal_services.portal_services_home"))
url = build_otb_cloud_handoff_url(uid, email)
return redirect(url)
@portal_services_bp.route("/portal/downloads/apps/<app_slug>/latest")
def portal_download_latest_app(app_slug):
client = get_portal_client()
if not client:
return redirect("/portal")
allowed_apps = {
"otb-cloud": {
"filename": "latest.apk",
"download_name": "otb-cloud-latest.apk",
},
"follow-me": {
"filename": "latest.apk",
"download_name": "follow-me-latest.apk",
},
}
if app_slug not in allowed_apps:
abort(404)
base_dir = Path(__file__).resolve().parents[2] / "downloads" / "apps" / app_slug
file_path = (base_dir / allowed_apps[app_slug]["filename"]).resolve()
try:
if base_dir.resolve() not in file_path.parents:
abort(403)
if not file_path.exists() or not file_path.is_file():
abort(404)
except Exception:
abort(404)
return send_file(
str(file_path),
as_attachment=True,
download_name=allowed_apps[app_slug]["download_name"],
mimetype="application/vnd.android.package-archive",
)