|
@@ -36,6 +36,101 @@
|
|
<main id="content" role="main">
|
|
<main id="content" role="main">
|
|
<div class="postindex">
|
|
<div class="postindex">
|
|
|
|
|
|
|
|
+ <article class="h-entry post-text" itemscope itemtype="http://schema.org/Blog">
|
|
|
|
+ <header>
|
|
|
|
+ <h1 class="p-name entry-title" itemprop="headline">
|
|
|
|
+ <a href="/posts/ssh-git-repo-docker.html" class="u-url">SSH Access to Git Repository in Docker</a>
|
|
|
|
+ </h1>
|
|
|
|
+ </header>
|
|
|
|
+ <div class="e-content entry-content">
|
|
|
|
+ <p>With the likes of <a href="https://gogs.io/">Gogs</a> and <a href="https://gitea.io">Gitea</a>,
|
|
|
|
+self-hosting a personal git service has become quite common. It’s also not
|
|
|
|
+unlikely that the software is run via docker but this brings a problem with
|
|
|
|
+regards to SSH access.</p>
|
|
|
|
+<p>Ideally, the git service container just exposes port 22 but this would conflict
|
|
|
|
+with the host’s own SSH service. One solution would be to just use different
|
|
|
|
+ports for the git SSH and host SSH and that’s perfectly fine. But we can also
|
|
|
|
+just have the host SSH service forward the request to the git service itself
|
|
|
|
+using the <code>command</code> option in <code>authorized_keys</code>. And as we’ll find out later,
|
|
|
|
+the git service itself is using this functionality.</p>
|
|
|
|
+<h2 id="how-git-over-ssh-works">How git over SSH works</h2>
|
|
|
|
+<p>When you do a <code>git push</code>, what actually happens is it runs <code>git-send-pack</code> which
|
|
|
|
+runs <code>git-receive-pack <directory></code> on the remote using SSH. The actual
|
|
|
|
+communication then just simply happens via stdin/stdout. Conversely, doing a
|
|
|
|
+<code>git pull</code> just runs <code>git-fetch-pack</code> and the somewhat confusingly named
|
|
|
|
+<code>git-upload-pack</code> on the remote.</p>
|
|
|
|
+<p>So far so good, but did you notice that when cloning via SSH, the remote is
|
|
|
|
+typically <code>git@github.com:org/repo</code>? If everyone SSHs in as the <code>git</code> user, how
|
|
|
|
+does the git service know which user is which? And how does it prevent users
|
|
|
|
+from accessing each other’s repositories?</p>
|
|
|
|
+<p>One typically thinks of <code>authorized_keys</code> as just a list of allowed SSH keys but
|
|
|
|
+it can do <a href="https://linux.die.net/man/8/sshd">much more than that</a>. Of particular
|
|
|
|
+interest is the <code>command</code> directive which gets run instead of the user supplied
|
|
|
|
+command. The original command is passed in as an environment variable
|
|
|
|
+<code>SSH_ORIGINAL_COMMAND</code> which can be used to check if we allow it to be run or
|
|
|
|
+not.</p>
|
|
|
|
+<p>So with an <code>authorized_keys</code> file like so:</p>
|
|
|
|
+<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">command="verify-user user-1" ssh-rsa ...
|
|
|
|
+command="verify-user user-1" ssh-ed25519 ...
|
|
|
|
+command="verify-user user-2" ssh-rsa ...
|
|
|
|
+command="verify-user user-3" ssh-rsa ...
|
|
|
|
+</code></pre></div><p>Each key is tied to a particular user by virtue of <code>command</code>. And <code>verify-user</code>
|
|
|
|
+can check the <code>SSH_ORIGINAL_COMMAND</code> if the particular user is allowed access to
|
|
|
|
+the particular repository. You can also implement additional restrictions like
|
|
|
|
+pull-only or push-only permissions with this setup. This is how both Gogs and
|
|
|
|
+Gitea work.</p>
|
|
|
|
+<h2 id="forwarding-git-ssh-to-docker">Forwarding git SSH to Docker</h2>
|
|
|
|
+<p>When running Gogs on the host, it’s typically run as the <code>git</code> user and when an
|
|
|
|
+SSH key is added or removed, it simply rewrites <code>~git/.ssh/authorized_keys</code>.
|
|
|
|
+Thus it just works with the host SSH service without problems. When running
|
|
|
|
+inside docker, one thing we can do is bind mount the host’s <code>~git/.ssh</code> folder
|
|
|
|
+into the docker container so that the host can authorize the SSH connections.</p>
|
|
|
|
+<p>The problem lies with the <code>command</code> which only exists inside the docker
|
|
|
|
+container itself. So any user trying to connect can authenticate successfully
|
|
|
|
+but will get a <code>command not found</code> error. For the Gogs docker image, the command
|
|
|
|
+looks like <code>/app/gogs/gogs serv key-1</code>. So we can just make <code>/app/gogs/gogs</code>
|
|
|
|
+available on the host and forward the command to the docker container.</p>
|
|
|
|
+<p><a href="https://docs.gitea.io/en-us/install-with-docker/#ssh-container-passthrough">Most</a>
|
|
|
|
+<a href="http://www.ateijelo.com/blog/2016/07/09/share-port-22-between-docker-gogs-ssh-and-local-system">instructions</a>
|
|
|
|
+I’ve seen with regards to this involves using <code>ssh</code> to connect to the internal
|
|
|
|
+docker SSH service but this just seems overly complicated to me. If you
|
|
|
|
+remember, at it’s core git really only communicates over stdin/stdout and SSH is
|
|
|
|
+just a means to get that.</p>
|
|
|
|
+<p>If all we need is for our shim <code>/app/gogs/gogs</code> to be able to run a command
|
|
|
|
+inside the docker container with stdin/stdout attached, then we can actually
|
|
|
|
+just do that with <code>docker exec</code>. So it can be something like this:</p>
|
|
|
|
+<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-shell" data-lang="shell"><span style="color:#0f0;font-weight:bold">#!/usr/bin/env bash
|
|
|
|
+</span><span style="color:#0f0;font-weight:bold"></span>
|
|
|
|
+<span style="color:#007f7f"># Requires the following in sudoers</span>
|
|
|
|
+<span style="color:#007f7f"># git ALL=(ALL) NOPASSWD: /app/gogs/gogs</span>
|
|
|
|
+<span style="color:#007f7f"># Defaults:git env_keep=SSH_ORIGINAL_COMMAND</span>
|
|
|
|
+
|
|
|
|
+GOGS_CONTAINER=git-gogs-1
|
|
|
|
+
|
|
|
|
+<span style="color:#fff;font-weight:bold">if</span> [[ $EUID -ne <span style="color:#ff0;font-weight:bold">0</span> ]]; <span style="color:#fff;font-weight:bold">then</span>
|
|
|
|
+ <span style="color:#fff;font-weight:bold">exec</span> sudo <span style="color:#0ff;font-weight:bold">"</span>$0<span style="color:#0ff;font-weight:bold">"</span> <span style="color:#0ff;font-weight:bold">"</span>$@<span style="color:#0ff;font-weight:bold">"</span>
|
|
|
|
+<span style="color:#fff;font-weight:bold">fi</span>
|
|
|
|
+
|
|
|
|
+<span style="color:#fff;font-weight:bold">if</span> [ <span style="color:#0ff;font-weight:bold">"</span>$1<span style="color:#0ff;font-weight:bold">"</span> != <span style="color:#0ff;font-weight:bold">"serv"</span> ]; <span style="color:#fff;font-weight:bold">then</span>
|
|
|
|
+ <span style="color:#fff;font-weight:bold">exit</span> <span style="color:#ff0;font-weight:bold">1</span>
|
|
|
|
+<span style="color:#fff;font-weight:bold">fi</span>
|
|
|
|
+
|
|
|
|
+<span style="color:#fff;font-weight:bold">exec</span> docker <span style="color:#fff;font-weight:bold">exec</span> -i -u git -e <span style="color:#0ff;font-weight:bold">"SSH_ORIGINAL_COMMAND=</span>$SSH_ORIGINAL_COMMAND<span style="color:#0ff;font-weight:bold">"</span> <span style="color:#0ff;font-weight:bold">"</span>$GOGS_CONTAINER<span style="color:#0ff;font-weight:bold">"</span> /app/gogs/gogs <span style="color:#0ff;font-weight:bold">"</span>$@<span style="color:#0ff;font-weight:bold">"</span>
|
|
|
|
+</code></pre></div><p>So for git SSH access to Gogs running in docker, the necessary steps here are:</p>
|
|
|
|
+<ol>
|
|
|
|
+<li>Have a <code>git</code> user on the host</li>
|
|
|
|
+<li>Bind mount <code>~git/.ssh</code> to <code>/data/git/.ssh</code> in the Gogs container</li>
|
|
|
|
+<li>Add the shim script to <code>/app/gogs/gogs</code> (make sure it’s owned by root and
|
|
|
|
+is chmod-ed <code>0755</code>)</li>
|
|
|
|
+<li>Add the listed sudoers rules</li>
|
|
|
|
+</ol>
|
|
|
|
+
|
|
|
|
+ </div>
|
|
|
|
+ <small class="dateline">Posted: <time class="published dt-published" itemprop="datePublished" datetime="2022-01-23">2022-01-23</time></small>
|
|
|
|
+ | <small class="commentline"><a href="/posts/ssh-git-repo-docker.html#isso-thread">Comments</a></small>
|
|
|
|
+ </article>
|
|
|
|
+ </article>
|
|
|
|
+
|
|
<article class="h-entry post-text" itemscope itemtype="http://schema.org/Blog">
|
|
<article class="h-entry post-text" itemscope itemtype="http://schema.org/Blog">
|
|
<header>
|
|
<header>
|
|
<h1 class="p-name entry-title" itemprop="headline">
|
|
<h1 class="p-name entry-title" itemprop="headline">
|
|
@@ -173,154 +268,6 @@ want to contribute music or sound effects, I’d gladly appreciate it.</p>
|
|
</article>
|
|
</article>
|
|
</article>
|
|
</article>
|
|
|
|
|
|
- <article class="h-entry post-text" itemscope itemtype="http://schema.org/Blog">
|
|
|
|
- <header>
|
|
|
|
- <h1 class="p-name entry-title" itemprop="headline">
|
|
|
|
- <a href="/posts/openpreppad.html" class="u-url">OpenPrepPad</a>
|
|
|
|
- </h1>
|
|
|
|
- </header>
|
|
|
|
- <div class="e-content entry-content">
|
|
|
|
- <p>Smart electronics and IoT (Internet of Things) are all the rage these days. You
|
|
|
|
-have a lot of companies sprout up trying to make the next big thing, which also
|
|
|
|
-leads to a lot of failures big and small. Pebble, the maker of my smartwatch,
|
|
|
|
-got bought out by Fitbit recently. This left watch owners without any official
|
|
|
|
-support, but thankfully, community members <a href="http://rebble.io/">stepped up</a> to continue
|
|
|
|
-maintaining it.</p>
|
|
|
|
-<p>Another casualty of the IoT boom was the <a href="http://theorangechef.com/">Orange Chef</a> <a href="https://www.amazon.com/Orange-Chef-Smart-Scale-Silver/dp/B00KFW8L90">Prep Pad</a>. It’s a
|
|
|
|
-bluetooth connected weighing scale to make it easy to track your calories and
|
|
|
|
-carb/fat/protein intake. My dad bought it last year only to find out that the
|
|
|
|
-app was incredibly buggy. The search function doesn’t work which makes the whole
|
|
|
|
-thing practically useless. I also found out later that you can’t even download
|
|
|
|
-the app to use the scale anymore.</p>
|
|
|
|
-<p><strong>Note</strong> I just found out as I was writing this post that it <em>may</em> get supported
|
|
|
|
-by <a href="http://www.prnewswire.com/news-releases/perfect-company-acquires-orange-chefs-prep-pad-related-ip-continues-momentum-in-the-connected-kitchen-300383178.html">another company</a>.</p>
|
|
|
|
-<p>So the app is useless, but at least you can use it as a scale, right?</p>
|
|
|
|
-<p><img src="/galleries/openpreppad/preppad.jpg" alt="Prep Pad"></p>
|
|
|
|
-<p>Nope. The device has no display whatsoever. The only controls on it are the
|
|
|
|
-on/off button and a green LED that isn’t even that useful at telling you whether
|
|
|
|
-it’s on or not. At this point, it’s just a giant paperweight.</p>
|
|
|
|
-<h2 id="reverse-engineering">Reverse Engineering</h2>
|
|
|
|
-<p>Since I essentially had nothing to lose, I tried poking at the thing to figure
|
|
|
|
-out how it works. I didn’t really have experience with bluetooth besides trying
|
|
|
|
-to get my bluetooth mouse connected on Linux. The main thing I used then was
|
|
|
|
-<code>bluetoothctl</code> which is essentially a CLI for managing bluetooth devices so I
|
|
|
|
-started there.</p>
|
|
|
|
-<p>I started up <code>bluetoothctl</code> and turned on the Prep Pad. And it showed up!</p>
|
|
|
|
-<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[bluetooth]# power on
|
|
|
|
-[CHG] Controller ... Class: 0x00010c
|
|
|
|
-Changing power on succeeded
|
|
|
|
-[CHG] Controller ... Powered: yes
|
|
|
|
-[bluetooth]# scan on
|
|
|
|
-Discovery started
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB RSSI: -51
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB Name: CHSLEEV_00
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB Alias: CHSLEEV_00
|
|
|
|
-</code></pre></div><p>I then connected to it, which was surprisingly easy.</p>
|
|
|
|
-<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[bluetooth]# connect 1C:BA:8C:21:7C:BB
|
|
|
|
-Attempting to connect to 1C:BA:8C:21:7C:BB
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB Connected: yes
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB Name: CH BTScale_00
|
|
|
|
-[CHG] Device 1C:BA:8C:21:7C:BB Alias: CH BTScale_00
|
|
|
|
-</code></pre></div><p>Now normally, when you turn the device on, the green light flashes occasionally.
|
|
|
|
-Once I connected to it, the green light stayed on permanently. Clearly, I was
|
|
|
|
-making progress. A lot of services were also discovered but I had no idea what
|
|
|
|
-those things were at that point.</p>
|
|
|
|
-<p>After a lot of poking around, I could check the general device information. You
|
|
|
|
-could get the hardware, software and firmware version. There’s also the device
|
|
|
|
-serial number which was nowhere on the actual physical device.</p>
|
|
|
|
-<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017
|
|
|
|
-[CH BTScale_00:/service0010/char0017]# attribute-info
|
|
|
|
-Characteristic - Firmware Revision String
|
|
|
|
- UUID: 00002a26-0000-1000-8000-00805f9b34fb
|
|
|
|
- Service: /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010
|
|
|
|
- Value: 0x31
|
|
|
|
- Value: 0x2e
|
|
|
|
- Value: 0x31
|
|
|
|
- Value: 0x33
|
|
|
|
- Value: 0x41
|
|
|
|
- Value: 0x00
|
|
|
|
- Flags: read
|
|
|
|
-[CH BTScale_00:/service0010/char0017]# read
|
|
|
|
-Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x2e
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x31
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x33
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x41
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0010/char0017 Value: 0x00
|
|
|
|
- 31 2e 31 33 41 00 1.13A.
|
|
|
|
-[CH BTScale_00:/service0010/char0017]#
|
|
|
|
-</code></pre></div><p>There was also a service which contained Accel Enable, Accel Range, Accel
|
|
|
|
-X-Coordinate, Accel Y-Coordinate, and Accel Z-Coordinate. I guess it stands for
|
|
|
|
-accelerometer, which is probably what it uses to weigh things.</p>
|
|
|
|
-<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026
|
|
|
|
-[CH BTScale_00:/service0023/char0024/desc0026]# read
|
|
|
|
-Attempting to read /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x41
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x63
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x20
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x45
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6e
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x61
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x62
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x6c
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024/desc0026 Value: 0x65
|
|
|
|
- 41 63 63 65 6c 20 45 6e 61 62 6c 65 Accel Enable
|
|
|
|
-</code></pre></div><p>I couldn’t read from any of the Accel Coordinates. It kept saying permission
|
|
|
|
-denied. I could however, notify on them. But that didn’t yield anything as well.
|
|
|
|
-What I <em>could</em> read was Accel Enable, which was set to 00. I guess that means it
|
|
|
|
-was off. After writing 01 to Accel Enable, I found I could get values out of
|
|
|
|
-Accel X-Coordinate! Also, the green LED which was permanently on turned off.</p>
|
|
|
|
-<div class="highlight"><pre tabindex="0" style="color:#e5e5e5;background-color:#000;-moz-tab-size:4;-o-tab-size:4;tab-size:4"><code class="language-text" data-lang="text">[CHSLEEV_00]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024
|
|
|
|
-[CH BTScale_00:/service0023/char0024]# write 01
|
|
|
|
-Attempting to write /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char0024
|
|
|
|
-[CH BTScale_00:/service0023/char0024]# select-attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a
|
|
|
|
-[CH BTScale_00:/service0023/char002a]# notify on
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Notifying: yes
|
|
|
|
-Notify started
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x5b
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x55
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x59
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0xa3
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x02
|
|
|
|
-[CHG] Attribute /org/bluez/hci0/dev_1C_BA_8C_21_7C_BB/service0023/char002a Value: 0x00
|
|
|
|
-</code></pre></div><p>I tried pressing the scale down a few times, and the values changed accordingly.
|
|
|
|
-Now, I just had to figure out how to convert the values into grams. It looked
|
|
|
|
-like the values were 32-bit integers sent as 4 bytes. In the above example it
|
|
|
|
-would be <code>0x0002a35b</code>, <code>0x0002a355</code>, <code>0x0002a359</code> or 172891, 172855, 172899. The
|
|
|
|
-values also decrease as you exert more effort on the scale. So assuming you take
|
|
|
|
-the initial value as <em>tare</em>, you simply subtract any succeeding value from that
|
|
|
|
-<em>tare</em> and you get the “weight”.</p>
|
|
|
|
-<p>The values I got didn’t seem to be in grams though. After weighing some things
|
|
|
|
-on an actual scale and comparing the values I got, I found I can just divide the
|
|
|
|
-values by 14 and get something in grams. That 14 is entirely a magic number
|
|
|
|
-though and I have no idea whether other Prep Pad’s would have the same constant.</p>
|
|
|
|
-<h2 id="openpreppad">OpenPrepPad</h2>
|
|
|
|
-<p>With all that figured out, I went ahead and made a <a href="https://github.com/thatsmydoing/openpreppad">simple CLI application</a>
|
|
|
|
-to interface with the Prep Pad. Ironically, node was the simplest thing I found
|
|
|
|
-that had <a href="https://github.com/sandeepmistry/noble">nice bluetooth library support</a> so that’s what I wrote it in. I
|
|
|
|
-also added most of the technical details in the README for that as well.</p>
|
|
|
|
-<p>While this is all well and cool, I doubt the intersection of Linux users and
|
|
|
|
-people who <!-- raw HTML omitted -->got ripped off<!-- raw HTML omitted --> bought the Prep Pad is anyone besides me. In
|
|
|
|
-light of that, I’m in the process of making a React Native version of the app,
|
|
|
|
-but that’s still a work in progress. Who knows, if the new owners of Prep Pad
|
|
|
|
-are good, I might not even need to finish it.</p>
|
|
|
|
-
|
|
|
|
- </div>
|
|
|
|
- <small class="dateline">Posted: <time class="published dt-published" itemprop="datePublished" datetime="2017-01-15">2017-01-15</time></small>
|
|
|
|
- | <small class="commentline"><a href="/posts/openpreppad.html#isso-thread">Comments</a></small>
|
|
|
|
- </article>
|
|
|
|
- </article>
|
|
|
|
-
|
|
|
|
</div>
|
|
</div>
|
|
<nav class="postindexpager">
|
|
<nav class="postindexpager">
|
|
<ul class="pager clearfix">
|
|
<ul class="pager clearfix">
|