Added basic authentication

This commit is contained in:
ArabCoders 2024-07-18 15:43:32 +03:00
parent b5673b9822
commit be68cf13e5
4 changed files with 57 additions and 10 deletions

12
Pipfile.lock generated
View file

@ -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": [

View file

@ -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

View file

@ -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:

View file

@ -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(),