<?xml version="1.0" encoding="UTF-8"?>
<!-- generator="FeedCreator 1.8" -->
<?xml-stylesheet href="https://baszerr.eu/lib/exe/css.php?s=feed" type="text/css"?>
<rss version="2.0">
    <channel xmlns:g="http://base.google.com/ns/1.0">
        <title>BaSzErr - blog:2025:07:11</title>
        <description></description>
        <link>https://baszerr.eu/</link>
        <lastBuildDate>Fri, 17 Apr 2026 12:54:37 +0000</lastBuildDate>
        <generator>FeedCreator 1.8</generator>
        <image>
            <url>https://baszerr.eu/lib/exe/fetch.php?media=wiki:dokuwiki.svg</url>
            <title>BaSzErr</title>
            <link>https://baszerr.eu/</link>
        </image>
        <item>
            <title>2025-07-11_-_mjpeg_and_basic_auth_on_client_side</title>
            <link>https://baszerr.eu/doku.php?id=blog:2025:07:11:2025-07-11_-_mjpeg_and_basic_auth_on_client_side</link>
            <description>
&lt;h1 class=&quot;sectionedit1&quot; id=&quot;mjpeg_and_basic_auth_on_client_side&quot;&gt;2025-07-11 - mjpeg and basic auth on client side&lt;/h1&gt;
&lt;div class=&quot;level1&quot;&gt;

&lt;p&gt;
some time ago, as a part of my &lt;a href=&quot;https://github.com/el-bart/Voron_stuff/&quot; class=&quot;urlextern&quot; title=&quot;https://github.com/el-bart/Voron_stuff/&quot; rel=&quot;ugc nofollow&quot;&gt;Voron activities&lt;/a&gt;, i decided to add a camera to monitor the print. it was an interesting quest to find nice, and easy to use options, while minimizing external dependencies. finally i&amp;#039;ve settled for &lt;a href=&quot;https://en.wikipedia.org/wiki/MJPEG&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/MJPEG&quot;&gt;MJPEG&lt;/a&gt; + reverse proxy on &lt;a href=&quot;https://en.wikipedia.org/wiki/nginx&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/nginx&quot;&gt;nginx&lt;/a&gt;… but that&amp;#039;s for another blog entry. :)
&lt;/p&gt;

&lt;p&gt;
here, the interesting part was client side. since i used &lt;code&gt;nginx&lt;/code&gt; it was very natural to just do HTTPS + basic auth for auth and encryption.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;2025-07-11 - mjpeg and basic auth on client side&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;mjpeg_and_basic_auth_on_client_side&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:1,&amp;quot;range&amp;quot;:&amp;quot;1-568&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit2&quot; id=&quot;take_1ffmpeg&quot;&gt;take 1: ffmpeg&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
&lt;a href=&quot;https://en.wikipedia.org/wiki/ffmpeg&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/ffmpeg&quot;&gt;ffmpeg&lt;/a&gt; has a built-in support for both MJPEG and basic auth, so it was supposed to be a smooth sailing… however there was a small catch – basic auth is passed as a part of the &lt;abbr title=&quot;Uniform Resource Identifier&quot;&gt;URI&lt;/abbr&gt;, e.g.:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;https://user:mysecret@camera.address/some_stream&lt;/pre&gt;

&lt;p&gt;
combining this with &lt;code&gt;ffmpeg&lt;/code&gt; was straight forward:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;ffmpeg \
  -f mjpeg -framerate 25 -r 25 -i https://user:mysecret@camera.address/some_stream \
  -vcodec copy -an \
  output.avi&lt;/pre&gt;

&lt;p&gt;
…and guess what happens when you run &lt;code&gt;ps&lt;/code&gt; command? yes – the password is in clear text. it turns out that &lt;code&gt;ffmpeg&lt;/code&gt; does not sanitize the input secret. it also does not have any option 
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;take 1: ffmpeg&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;take_1ffmpeg&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:2,&amp;quot;range&amp;quot;:&amp;quot;569-1227&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit3&quot; id=&quot;take_2curl_ffmpeg&quot;&gt;take 2: curl + ffmpeg&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
the next, natural option was to use &lt;a href=&quot;https://en.wikipedia.org/wiki/curl&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/curl&quot;&gt;curl&lt;/a&gt;:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;curl https://user:mysecret@camera.address/some_stream | ffmpeg -i - ...&lt;/pre&gt;

&lt;p&gt;
then &lt;code&gt;ps&lt;/code&gt;… and still the same – secret is there. :/
&lt;/p&gt;

&lt;p&gt;
interestingly enough – there was no way to read a series of links from a file in &lt;code&gt;curl&lt;/code&gt;. i guess the assumption was that one can always do a &lt;code&gt;for&lt;/code&gt; loop in shell, or similar. it however does not cover my case of hiding basic auth details.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;take 2: curl + ffmpeg&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;take_2curl_ffmpeg&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:3,&amp;quot;range&amp;quot;:&amp;quot;1228-1688&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit4&quot; id=&quot;take_3wget_ffmpeg&quot;&gt;take 3: wget + ffmpeg&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
the next natural take was:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;curl -O - https://user:mysecret@camera.address/some_stream | ffmpeg -i - ...&lt;/pre&gt;

&lt;p&gt;
as you probably already expect – password was still visible in process list. this time however, &lt;code&gt;wget&lt;/code&gt; was an ace upon its sleeve – it can read links from file!
&lt;/p&gt;

&lt;p&gt;
it&amp;#039;s now enough to prepare a file:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;touch ~/.my_camera.cfg
chmod $_
vim $_&lt;/pre&gt;

&lt;p&gt;
and put our magic string here:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;https://user:mysecret@camera.address/some_stream&lt;/pre&gt;

&lt;p&gt;
now to run it just use the input file, instead of a direct link:
&lt;/p&gt;
&lt;pre class=&quot;code&quot;&gt;wget -O - -i ~/.my_camera.cfg | ffmpeg -i - ...&lt;/pre&gt;

&lt;p&gt;
and voila! stream is being recorded, while password is ~secure in a config file.
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;take 3: wget + ffmpeg&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;take_3wget_ffmpeg&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:4,&amp;quot;range&amp;quot;:&amp;quot;1689-2355&amp;quot;} --&gt;
&lt;h3 class=&quot;sectionedit5&quot; id=&quot;full_script&quot;&gt;full script&lt;/h3&gt;
&lt;div class=&quot;level3&quot;&gt;

&lt;p&gt;
to make thins complete we add 2 more things on top:
&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; H.264 compression&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;level1&quot;&gt;&lt;div class=&quot;li&quot;&gt; file segmentation (10min each)&lt;/div&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;code bash&quot;&gt;&lt;span class=&quot;co0&quot;&gt;#!/bin/bash&lt;/span&gt;
&lt;span class=&quot;kw1&quot;&gt;set&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;-eu&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;-o&lt;/span&gt; pipefail
&lt;span class=&quot;re2&quot;&gt;app&lt;/span&gt;=$&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;basename&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;$0&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;re2&quot;&gt;crt&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$HOME&lt;/span&gt;/.config/camera/mycam.crt&amp;quot;&lt;/span&gt;
&lt;span class=&quot;re2&quot;&gt;link&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$HOME&lt;/span&gt;/.config/camera/mycam.link&amp;quot;&lt;/span&gt; &lt;span class=&quot;co0&quot;&gt;# &amp;lt;&amp;lt; secret password lives here&lt;/span&gt;
&lt;span class=&quot;re2&quot;&gt;outdir_base&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$HOME&lt;/span&gt;/recordings&amp;quot;&lt;/span&gt;
&lt;span class=&quot;re2&quot;&gt;fps&lt;/span&gt;=&lt;span class=&quot;nu0&quot;&gt;25&lt;/span&gt;
&lt;span class=&quot;re2&quot;&gt;outdir&lt;/span&gt;=&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$outdir_base&lt;/span&gt;/&lt;span class=&quot;es4&quot;&gt;$(date +%Y-%m-%d_%H%M%d)&lt;/span&gt;&amp;quot;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;kw2&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;re5&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$outdir&lt;/span&gt;&amp;quot;&lt;/span&gt;
&lt;span class=&quot;kw3&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$app&lt;/span&gt;: recording to &lt;span class=&quot;es2&quot;&gt;$outdir&lt;/span&gt;&amp;quot;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;re2&quot;&gt;wget_cmd&lt;/span&gt;=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;wget&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
wget_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;--quiet&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
wget_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;--timeout=&lt;span class=&quot;nu0&quot;&gt;5&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
wget_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;--ca-certificate &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$crt&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
wget_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-O -&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
wget_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-i &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$link&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;re2&quot;&gt;ffmpeg_cmd&lt;/span&gt;=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;kw2&quot;&gt;ffmpeg&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-f mjpeg&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-framerate &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$fps&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;co0&quot;&gt;# input frame rate - apparently this is what source provides atm...&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-i -&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-r &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$fps&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;co0&quot;&gt;# output frame rate&lt;/span&gt;
&lt;span class=&quot;co0&quot;&gt;# compress input&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-vcodec h264 &lt;span class=&quot;re5&quot;&gt;-preset&lt;/span&gt; fast &lt;span class=&quot;re5&quot;&gt;-crf&lt;/span&gt; &lt;span class=&quot;nu0&quot;&gt;23&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;co0&quot;&gt;# disable audio (if present)&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-an&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&lt;span class=&quot;co0&quot;&gt;# segment output&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-f segment&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-segment_time &lt;span class=&quot;nu0&quot;&gt;600&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt; &lt;span class=&quot;co0&quot;&gt;# seconds&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;-reset_timestamps &lt;span class=&quot;nu0&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
ffmpeg_cmd+=&lt;span class=&quot;br0&quot;&gt;&amp;#40;&lt;/span&gt;&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es2&quot;&gt;$outdir&lt;/span&gt;/%06d.avi&amp;quot;&lt;/span&gt;&lt;span class=&quot;br0&quot;&gt;&amp;#41;&lt;/span&gt;
&amp;nbsp;
&lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es3&quot;&gt;${wget_cmd[@]}&lt;/span&gt;&amp;quot;&lt;/span&gt; &lt;span class=&quot;sy0&quot;&gt;|&lt;/span&gt; &lt;span class=&quot;st0&quot;&gt;&amp;quot;&lt;span class=&quot;es3&quot;&gt;${ffmpeg_cmd[@]}&lt;/span&gt;&amp;quot;&lt;/span&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;full script&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;full_script&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:0,&amp;quot;secid&amp;quot;:5,&amp;quot;range&amp;quot;:&amp;quot;2356-3454&amp;quot;} --&gt;
&lt;h2 class=&quot;sectionedit6&quot; id=&quot;final_notes&quot;&gt;final notes&lt;/h2&gt;
&lt;div class=&quot;level2&quot;&gt;

&lt;p&gt;
while the need to combine &lt;code&gt;ffmpeg&lt;/code&gt; with downloader was anyway a must have, due to custom HTTPS certificates used for the local connection, the lack of easy basic auth covering up was a bit of a surprise to me. while it&amp;#039;s kinda ok for app not overwriting password in its &lt;code&gt;argv&lt;/code&gt; (it can give a false sense of security, as there&amp;#039;s still a race when starting application – password is briefly visible then), not being able to pass it via some env or a secrets file was a bit of a head-scratcher for me.
&lt;/p&gt;

&lt;p&gt;
the good news is that &lt;a href=&quot;https://en.wikipedia.org/wiki/FLOSS&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/FLOSS&quot;&gt;FLOSS&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Unix philosophy&quot; class=&quot;interwiki iw_wp&quot; title=&quot;https://en.wikipedia.org/wiki/Unix philosophy&quot;&gt;the UNIX way&lt;/a&gt; of combining things with pipes once again shined and saved the day! :)
&lt;/p&gt;

&lt;/div&gt;
&lt;!-- EDIT{&amp;quot;target&amp;quot;:&amp;quot;section&amp;quot;,&amp;quot;name&amp;quot;:&amp;quot;final notes&amp;quot;,&amp;quot;hid&amp;quot;:&amp;quot;final_notes&amp;quot;,&amp;quot;codeblockOffset&amp;quot;:1,&amp;quot;secid&amp;quot;:6,&amp;quot;range&amp;quot;:&amp;quot;3455-&amp;quot;} --&gt;</description>
            <author>anonymous@undisclosed.example.com (Anonymous)</author>
            <pubDate>Fri, 11 Jul 2025 07:09:02 +0000</pubDate>
        </item>
    </channel>
</rss>
