Skip to content

Commit

Permalink
Merge branch 'v2.0'
Browse files Browse the repository at this point in the history
# Conflicts:
#	docs/README.html
#	docs/README.md
#	docs/_sources/README.md.txt
#	docs/index.html
#	docs/searchindex.js
#	pystream/models/squire.py
  • Loading branch information
dormant-user committed Jan 30, 2024
2 parents 75023ea + 3a8cad3 commit 6a35eda
Show file tree
Hide file tree
Showing 30 changed files with 821 additions and 199 deletions.
11 changes: 4 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Pypi-format](https://img.shields.io/pypi/format/stream-localhost)](https://pypi.org/project/stream-localhost/#files)
[![Pypi-status](https://img.shields.io/pypi/status/stream-localhost)][pypi]

# Video Streaming
# PyStream
Python module to, stream videos via authenticated sessions using FastAPI

## Install
Expand All @@ -24,9 +24,8 @@ import pystream

if __name__ == '__main__':
kwargs = dict(
username="foo",
password="bar",
video_source=os.path.join(os.path.expanduser('~'), 'Downloads'),
authorization={"Alan Turing": "Pr0gRamM1ng", "Linus Torvalds": "LinuxOS"},
video_source=os.path.join(os.path.expanduser('~'), 'Downloads')
)
# Add the following to host on local IP address, skip for localhost (127.0.0.1)
# kwargs["video_host"] = pystream.utils.get_local_ip()
Expand All @@ -38,9 +37,7 @@ if __name__ == '__main__':
> Refer the [wiki page][wiki] for more information.
**Mandatory**
- **USERNAME**: Any username of choice.
- **PASSWORD**: Any password of choice.
- **SECRET**: Any private key to encode and decode JWT.
- **AUTHORIZATION**: Dictionary of key-value pairs with `username` as key and `password` as value.
- **VIDEO_SOURCE**: Source path for video files.
> :bulb:   Files starting with `_` _(underscore)_ and `.` _(dot)_ will be ignored
Expand Down
39 changes: 39 additions & 0 deletions authentication.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Authentication
`PyStream` uses two ways of authentication, the `username` and `password` to gain access to the server and
a `session_token` generated by the server to access directories and streaming content.

### Username and Password
> [Signature Authentication][signature-authentication]
#### Frontend
- UI creates hex values for username and password using native JS
- These hex values are then used the calculate the hash
- Calculated hash is then base64 encoded using native JS, before sending the signature to the API in an authorization header

#### Backend
- API decodes the base64 encoded ascii string, then decodes the HEX received in authorization header
- Then the value is broken down to, username, signature and timestamp
- The decoded username is used to get the stored password from env variables, which are then hex encoded
- API creates a hash signature using the hex username, hex password, and the timestamp
- These signatures are then compared for authentication purpose

### Session Token
> [Symmetric Encryption][symmetric-encryption]
- Once the login has been successful, the API creates a randomly generated 64 bit url safe token
- This token is stored as unique key for each user
- The API then forms a payload with the username, key, and the timestamp
- This payload is then encrypted using Cryptography's Fernet, which can be retrieved only using the key
- This encrypted payload is stored as a cookie before sending a `JSONResponse` with a `redirect_url`
> Since the UI uses `AJAX` for authentication POST call, a `RedirectResponse` from FastAPI will not work,
> as the call will simply follow the redirect to `GET` the content instead of redirecting the page.
- The `redirect_url` from the JSON response is fetched, to alter `location.href`
> This form of redirect will transfer cookies to the new page but not the headers,
> so the username and password are lost in the frontend at this point
- From then on, all calls to the backend including redirects, directory navigation and, streaming will carry the cookie
- The `session_token` is the only form of authentication from this point onward

### References
- [symmetric-encryption]
- [signature-authentication]

[symmetric-encryption]: https://cryptography.io/en/latest/fernet/
[signature-authentication]: https://developers.expediagroup.com/docs/products/rapid/resources/reference/signature-authentication
8 changes: 8 additions & 0 deletions doc_gen/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Stream-Localhost - A secured interface to stream videos
:caption: Read Me:

README
authentication

Main Module
===========
Expand Down Expand Up @@ -42,6 +43,13 @@ Images
:members:
:undoc-members:

Secure
======

.. automodule:: pystream.models.secure
:members:
:undoc-members:

Squire
======

Expand Down
37 changes: 23 additions & 14 deletions docs/README.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />

<title>Video Streaming &#8212; Stream documentation</title>
<title>PyStream &#8212; Stream documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/classic.css" />

Expand All @@ -18,6 +18,7 @@

<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Authentication" href="authentication.html" />
<link rel="prev" title="Stream-Localhost - A secured interface to stream videos" href="index.html" />
</head><body>
<div class="related" role="navigation" aria-label="related navigation">
Expand All @@ -29,11 +30,14 @@ <h3>Navigation</h3>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="authentication.html" title="Authentication"
accesskey="N">next</a> |</li>
<li class="right" >
<a href="index.html" title="Stream-Localhost - A secured interface to stream videos"
accesskey="P">previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Stream documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Video Streaming</a></li>
<li class="nav-item nav-item-this"><a href="">PyStream</a></li>
</ul>
</div>

Expand All @@ -49,8 +53,8 @@ <h3>Navigation</h3>
<p><a class="reference external" href="https://pypi.org/project/stream-localhost"><img alt="PyPI version shields.io" src="https://img.shields.io/pypi/v/stream-localhost" /></a>
<a class="reference external" href="https://pypi.org/project/stream-localhost/#files"><img alt="Pypi-format" src="https://img.shields.io/pypi/format/stream-localhost" /></a>
<a class="reference external" href="https://pypi.org/project/stream-localhost"><img alt="Pypi-status" src="https://img.shields.io/pypi/status/stream-localhost" /></a></p>
<section id="video-streaming">
<h1>Video Streaming<a class="headerlink" href="#video-streaming" title="Permalink to this heading"></a></h1>
<section id="pystream">
<h1>PyStream<a class="headerlink" href="#pystream" title="Permalink to this heading"></a></h1>
<p>Python module to, stream videos via authenticated sessions using FastAPI</p>
<section id="install">
<h2>Install<a class="headerlink" href="#install" title="Permalink to this heading"></a></h2>
Expand All @@ -66,9 +70,8 @@ <h2>Sample Usage<a class="headerlink" href="#sample-usage" title="Permalink to t

<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s1">&#39;__main__&#39;</span><span class="p">:</span>
<span class="n">kwargs</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span>
<span class="n">username</span><span class="o">=</span><span class="s2">&quot;foo&quot;</span><span class="p">,</span>
<span class="n">password</span><span class="o">=</span><span class="s2">&quot;bar&quot;</span><span class="p">,</span>
<span class="n">video_source</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">expanduser</span><span class="p">(</span><span class="s1">&#39;~&#39;</span><span class="p">),</span> <span class="s1">&#39;Downloads&#39;</span><span class="p">),</span>
<span class="n">authorization</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;Alan Turing&quot;</span><span class="p">:</span> <span class="s2">&quot;Pr0gRamM1ng&quot;</span><span class="p">,</span> <span class="s2">&quot;Linus Torvalds&quot;</span><span class="p">:</span> <span class="s2">&quot;LinuxOS&quot;</span><span class="p">},</span>
<span class="n">video_source</span><span class="o">=</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">expanduser</span><span class="p">(</span><span class="s1">&#39;~&#39;</span><span class="p">),</span> <span class="s1">&#39;Downloads&#39;</span><span class="p">)</span>
<span class="p">)</span>
<span class="c1"># Add the following to host on local IP address, skip for localhost (127.0.0.1)</span>
<span class="c1"># kwargs[&quot;video_host&quot;] = pystream.utils.get_local_ip()</span>
Expand All @@ -78,14 +81,12 @@ <h2>Sample Usage<a class="headerlink" href="#sample-usage" title="Permalink to t
<section id="env-variables">
<h3>Env Variables<a class="headerlink" href="#env-variables" title="Permalink to this heading"></a></h3>
<blockquote>
<div><p>:bulb:   Environment variables can <em>(optionally)</em> be loaded from any file.<br>
Refer the <a class="reference external" href="https://github.com/thevickypedia/pystream/wiki">wiki page</a> for more information.</p>
<div><p>:bulb:   Environment variables can be loaded from any file. <em>Filename defaults to <code class="docutils literal notranslate"><span class="pre">.env</span></code></em><br>
To use custom filenames, set the env var <code class="docutils literal notranslate"><span class="pre">env_file</span></code> as <code class="docutils literal notranslate"><span class="pre">key</span></code> and the <em>filename</em> as its <code class="docutils literal notranslate"><span class="pre">value</span></code></p>
</div></blockquote>
<p><strong>Mandatory</strong></p>
<ul class="simple">
<li><p><strong>USERNAME</strong>: Any username of choice.</p></li>
<li><p><strong>PASSWORD</strong>: Any password of choice.</p></li>
<li><p><strong>SECRET</strong>: Any private key to encode and decode JWT.</p></li>
<li><p><strong>AUTHORIZATION</strong>: Dictionary of key-value pairs with <code class="docutils literal notranslate"><span class="pre">username</span></code> as key and <code class="docutils literal notranslate"><span class="pre">password</span></code> as value.</p></li>
<li><p><strong>VIDEO_SOURCE</strong>: Source path for video files.</p></li>
</ul>
<blockquote>
Expand Down Expand Up @@ -158,7 +159,7 @@ <h2>License &amp; copyright<a class="headerlink" href="#license-copyright" title
<div>
<h3><a href="index.html">Table of Contents</a></h3>
<ul>
<li><a class="reference internal" href="#">Video Streaming</a><ul>
<li><a class="reference internal" href="#">PyStream</a><ul>
<li><a class="reference internal" href="#install">Install</a></li>
<li><a class="reference internal" href="#sample-usage">Sample Usage</a><ul>
<li><a class="reference internal" href="#env-variables">Env Variables</a></li>
Expand All @@ -180,6 +181,11 @@ <h4>Previous topic</h4>
<p class="topless"><a href="index.html"
title="previous chapter">Stream-Localhost - A secured interface to stream videos</a></p>
</div>
<div>
<h4>Next topic</h4>
<p class="topless"><a href="authentication.html"
title="next chapter">Authentication</a></p>
</div>
<div role="note" aria-label="source link">
<h3>This Page</h3>
<ul class="this-page-menu">
Expand Down Expand Up @@ -210,11 +216,14 @@ <h3>Navigation</h3>
<li class="right" >
<a href="py-modindex.html" title="Python Module Index"
>modules</a> |</li>
<li class="right" >
<a href="authentication.html" title="Authentication"
>next</a> |</li>
<li class="right" >
<a href="index.html" title="Stream-Localhost - A secured interface to stream videos"
>previous</a> |</li>
<li class="nav-item nav-item-0"><a href="index.html">Stream documentation</a> &#187;</li>
<li class="nav-item nav-item-this"><a href="">Video Streaming</a></li>
<li class="nav-item nav-item-this"><a href="">PyStream</a></li>
</ul>
</div>
<div class="footer" role="contentinfo">
Expand Down
16 changes: 6 additions & 10 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Pypi-format](https://img.shields.io/pypi/format/stream-localhost)](https://pypi.org/project/stream-localhost/#files)
[![Pypi-status](https://img.shields.io/pypi/status/stream-localhost)][pypi]

# Video Streaming
# PyStream
Python module to, stream videos via authenticated sessions using FastAPI

## Install
Expand All @@ -24,23 +24,20 @@ import pystream

if __name__ == '__main__':
kwargs = dict(
username="foo",
password="bar",
video_source=os.path.join(os.path.expanduser('~'), 'Downloads'),
authorization={"Alan Turing": "Pr0gRamM1ng", "Linus Torvalds": "LinuxOS"},
video_source=os.path.join(os.path.expanduser('~'), 'Downloads')
)
# Add the following to host on local IP address, skip for localhost (127.0.0.1)
# kwargs["video_host"] = pystream.utils.get_local_ip()
asyncio.run(pystream.start(**kwargs))
```

### Env Variables
> :bulb: &nbsp; Environment variables can _(optionally)_ be loaded from any file.<br>
> Refer the [wiki page][wiki] for more information.
> :bulb: &nbsp; Environment variables can be loaded from any file. _Filename defaults to `.env`_<br>
> To use custom filenames, set the env var `env_file` as `key` and the _filename_ as its `value`
**Mandatory**
- **USERNAME**: Any username of choice.
- **PASSWORD**: Any password of choice.
- **SECRET**: Any private key to encode and decode JWT.
- **AUTHORIZATION**: Dictionary of key-value pairs with `username` as key and `password` as value.
- **VIDEO_SOURCE**: Source path for video files.
> :bulb: &nbsp; Files starting with `_` _(underscore)_ and `.` _(dot)_ will be ignored
Expand Down Expand Up @@ -109,4 +106,3 @@ Licensed under the [MIT License][license]
[isort]: https://pycqa.github.io/isort/
[sphinx]: https://www.sphinx-doc.org/en/master/man/sphinx-autogen.html
[runbook]: https://thevickypedia.github.io/pystream/
[wiki]: https://github.com/thevickypedia/pystream/wiki
16 changes: 6 additions & 10 deletions docs/_sources/README.md.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
[![Pypi-format](https://img.shields.io/pypi/format/stream-localhost)](https://pypi.org/project/stream-localhost/#files)
[![Pypi-status](https://img.shields.io/pypi/status/stream-localhost)][pypi]

# Video Streaming
# PyStream
Python module to, stream videos via authenticated sessions using FastAPI

## Install
Expand All @@ -24,23 +24,20 @@ import pystream

if __name__ == '__main__':
kwargs = dict(
username="foo",
password="bar",
video_source=os.path.join(os.path.expanduser('~'), 'Downloads'),
authorization={"Alan Turing": "Pr0gRamM1ng", "Linus Torvalds": "LinuxOS"},
video_source=os.path.join(os.path.expanduser('~'), 'Downloads')
)
# Add the following to host on local IP address, skip for localhost (127.0.0.1)
# kwargs["video_host"] = pystream.utils.get_local_ip()
asyncio.run(pystream.start(**kwargs))
```

### Env Variables
> :bulb: &nbsp; Environment variables can _(optionally)_ be loaded from any file.<br>
> Refer the [wiki page][wiki] for more information.
> :bulb: &nbsp; Environment variables can be loaded from any file. _Filename defaults to `.env`_<br>
> To use custom filenames, set the env var `env_file` as `key` and the _filename_ as its `value`

**Mandatory**
- **USERNAME**: Any username of choice.
- **PASSWORD**: Any password of choice.
- **SECRET**: Any private key to encode and decode JWT.
- **AUTHORIZATION**: Dictionary of key-value pairs with `username` as key and `password` as value.
- **VIDEO_SOURCE**: Source path for video files.
> :bulb: &nbsp; Files starting with `_` _(underscore)_ and `.` _(dot)_ will be ignored

Expand Down Expand Up @@ -109,4 +106,3 @@ Licensed under the [MIT License][license]
[isort]: https://pycqa.github.io/isort/
[sphinx]: https://www.sphinx-doc.org/en/master/man/sphinx-autogen.html
[runbook]: https://thevickypedia.github.io/pystream/
[wiki]: https://github.com/thevickypedia/pystream/wiki
39 changes: 39 additions & 0 deletions docs/_sources/authentication.md.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
## Authentication
`PyStream` uses two ways of authentication, the `username` and `password` to gain access to the server and
a `session_token` generated by the server to access directories and streaming content.

### Username and Password
> [Signature Authentication][signature-authentication]
#### Frontend
- UI creates hex values for username and password using native JS
- These hex values are then used the calculate the hash
- Calculated hash is then base64 encoded using native JS, before sending the signature to the API in an authorization header

#### Backend
- API decodes the base64 encoded ascii string, then decodes the HEX received in authorization header
- Then the value is broken down to, username, signature and timestamp
- The decoded username is used to get the stored password from env variables, which are then hex encoded
- API creates a hash signature using the hex username, hex password, and the timestamp
- These signatures are then compared for authentication purpose

### Session Token
> [Symmetric Encryption][symmetric-encryption]
- Once the login has been successful, the API creates a randomly generated 64 bit url safe token
- This token is stored as unique key for each user
- The API then forms a payload with the username, key, and the timestamp
- This payload is then encrypted using Cryptography's Fernet, which can be retrieved only using the key
- This encrypted payload is stored as a cookie before sending a `JSONResponse` with a `redirect_url`
> Since the UI uses `AJAX` for authentication POST call, a `RedirectResponse` from FastAPI will not work,
> as the call will simply follow the redirect to `GET` the content instead of redirecting the page.
- The `redirect_url` from the JSON response is fetched, to alter `location.href`
> This form of redirect will transfer cookies to the new page but not the headers,
> so the username and password are lost in the frontend at this point
- From then on, all calls to the backend including redirects, directory navigation and, streaming will carry the cookie
- The `session_token` is the only form of authentication from this point onward

### References
- [symmetric-encryption]
- [signature-authentication]

[symmetric-encryption]: https://cryptography.io/en/latest/fernet/
[signature-authentication]: https://developers.expediagroup.com/docs/products/rapid/resources/reference/signature-authentication
8 changes: 8 additions & 0 deletions docs/_sources/index.rst.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ Stream-Localhost - A secured interface to stream videos
:caption: Read Me:

README
authentication

Main Module
===========
Expand Down Expand Up @@ -42,6 +43,13 @@ Images
:members:
:undoc-members:

Secure
======

.. automodule:: pystream.models.secure
:members:
:undoc-members:

Squire
======

Expand Down
Loading

0 comments on commit 6a35eda

Please sign in to comment.