Added basic authentication
This commit is contained in:
parent
b5673b9822
commit
be68cf13e5
4 changed files with 57 additions and 10 deletions
12
Pipfile.lock
generated
12
Pipfile.lock
generated
|
|
@ -366,11 +366,11 @@
|
|||
},
|
||||
"croniter": {
|
||||
"hashes": [
|
||||
"sha256:f1f8ca0af64212fbe99b1bee125ee5a1b53a9c1b433968d8bca8817b79d237f3",
|
||||
"sha256:fdbb44920944045cc323db54599b321325141d82d14fa7453bc0699826bbe9ed"
|
||||
"sha256:1041b912b4b1e03751a0993531becf77851ae6e8b334c9c76ffeffb8f055f53f",
|
||||
"sha256:f15e80828d23920c4bb7f4d9340b932c9dcabecafc7775703c8b36d1253ed526"
|
||||
],
|
||||
"markers": "python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'",
|
||||
"version": "==2.0.5"
|
||||
"version": "==2.0.7"
|
||||
},
|
||||
"debugpy": {
|
||||
"hashes": [
|
||||
|
|
@ -403,11 +403,11 @@
|
|||
},
|
||||
"exceptiongroup": {
|
||||
"hashes": [
|
||||
"sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad",
|
||||
"sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"
|
||||
"sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b",
|
||||
"sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"
|
||||
],
|
||||
"markers": "python_version < '3.11'",
|
||||
"version": "==1.2.1"
|
||||
"version": "==1.2.2"
|
||||
},
|
||||
"frozenlist": {
|
||||
"hashes": [
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -16,7 +16,8 @@ YTPTube started as a fork of [meTube](https://github.com/alexta69/metube), Since
|
|||
* Tasks Runner. It allow you to queue channels for downloading using simple `json` file.
|
||||
* Webhook sender. It allow you to add webhook endpoints that receive events related to downloads using simple `json` file.
|
||||
* Multi-downloads support.
|
||||
|
||||
* Basic Authentication support.
|
||||
|
||||
### Tips
|
||||
Your `yt-dlp` config should include the following options for optimal working conditions.
|
||||
|
||||
|
|
@ -78,6 +79,8 @@ Certain values can be set via environment variables, using the `-e` parameter on
|
|||
* __YTP_MAX_WORKERS__: How many works to use for downloads. Defaults to `1`.
|
||||
* __YTP_STREAMER_VCODEC__: The video codec to use for in-browser streaming. Defaults to `libx264`.
|
||||
* __YTP_STREAMER_ACODEC__: The audio codec to use for in-browser streaming. Defaults to `aac`.
|
||||
* __YTP_AUTH_USERNAME__: Username for basic authentication. Defaults open for all
|
||||
* __YTP_AUTH_PASSWORD__: Password for basic authentication. Defaults open for all.
|
||||
|
||||
## Running behind a reverse proxy
|
||||
|
||||
|
|
@ -285,6 +288,14 @@ The `config/webhooks.json`, is a json file, which can be used to add webhook end
|
|||
]
|
||||
```
|
||||
|
||||
## Authentication
|
||||
|
||||
To enable basic authentication, set the `YTP_AUTH_USERNAME` and `YTP_AUTH_PASSWORD` environment variables. And restart the container.
|
||||
This will prompt the user to enter the username and password before accessing the web interface/API.
|
||||
As this is a simple basic authentication, if your browser doesn't show the prompt, you can use the following URL
|
||||
|
||||
`http://username:password@your_ytptube_url:port`
|
||||
|
||||
# Social contact
|
||||
|
||||
If you have short or quick questions, you are free to join my [discord server](https://discord.gg/G3GpVR8xpb) and ask
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ class Config:
|
|||
streamer_vcodec = 'libx264'
|
||||
streamer_acodec = 'aac'
|
||||
|
||||
auth_username: str = None
|
||||
auth_password: str = None
|
||||
|
||||
ytdlp_version: str = YTDLP_VERSION
|
||||
|
||||
_int_vars: tuple = ('port', 'max_workers', 'socket_timeout', 'extract_info_timeout',)
|
||||
|
|
@ -170,6 +173,9 @@ class Config:
|
|||
|
||||
LOG.info(f'Keep temp: {self.temp_keep}')
|
||||
|
||||
if self.auth_password and self.auth_username:
|
||||
LOG.warn(f"Basic Auth enabled with username: '{self.auth_username}'.")
|
||||
|
||||
self.started = time.time()
|
||||
|
||||
def _getAttributes(self) -> dict:
|
||||
|
|
|
|||
36
app/main.py
36
app/main.py
|
|
@ -1,17 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
import asyncio
|
||||
import base64
|
||||
from datetime import datetime
|
||||
import json
|
||||
import os
|
||||
import random
|
||||
import selectors
|
||||
import time
|
||||
from Config import Config
|
||||
from DownloadQueue import DownloadQueue
|
||||
from Utils import ObjectSerializer, Notifier, isDownloaded, load_file
|
||||
from aiohttp import web, client
|
||||
from aiohttp.web import Request, Response
|
||||
from aiohttp.web import Request, Response, RequestHandler
|
||||
from Webhooks import Webhooks
|
||||
from player.M3u8 import M3u8
|
||||
from player.Segments import Segments
|
||||
|
|
@ -20,7 +20,6 @@ import logging
|
|||
import caribou
|
||||
import sqlite3
|
||||
from aiocron import crontab
|
||||
from aiohttp.helpers import parse_http_date
|
||||
import magic
|
||||
|
||||
LOG = logging.getLogger('app')
|
||||
|
|
@ -91,6 +90,12 @@ class Main:
|
|||
self.serializer = ObjectSerializer()
|
||||
|
||||
self.app = web.Application()
|
||||
|
||||
if self.config.auth_username and self.config.auth_password:
|
||||
self.app.middlewares.append(
|
||||
Main.basic_auth(self.config.auth_username, self.config.auth_password)
|
||||
)
|
||||
|
||||
self.sio = socketio.AsyncServer(cors_allowed_origins='*')
|
||||
self.sio.attach(self.app, socketio_path=self.config.url_prefix + 'socket.io')
|
||||
|
||||
|
|
@ -120,6 +125,31 @@ class Main:
|
|||
print=lambda _: LOG.info(start)
|
||||
)
|
||||
|
||||
def basic_auth(username: str, password: str):
|
||||
@web.middleware
|
||||
async def middleware_handler(request: Request, handler: RequestHandler) -> Response:
|
||||
auth_header = request.headers.get('Authorization')
|
||||
|
||||
if auth_header is None:
|
||||
return web.Response(status=401, headers={
|
||||
'WWW-Authenticate': 'Basic realm="Authorization Required."',
|
||||
}, text='Unauthorized.')
|
||||
|
||||
auth_type, encoded_credentials = auth_header.split(' ', 1)
|
||||
|
||||
if 'basic' != auth_type.lower():
|
||||
return web.Response(status=401, text="Unsupported authentication method.")
|
||||
|
||||
decoded_credentials = base64.b64decode(encoded_credentials).decode('utf-8')
|
||||
user_name, _, user_password = decoded_credentials.partition(':')
|
||||
|
||||
if user_name != username or user_password != password:
|
||||
return web.Response(status=401, text='Unauthorized (Invalid credentials).')
|
||||
|
||||
return await handler(request)
|
||||
|
||||
return middleware_handler
|
||||
|
||||
async def connect(self, sid, _):
|
||||
data: dict = {
|
||||
**self.queue.get(),
|
||||
|
|
|
|||
Loading…
Reference in a new issue