After Angular, React.js and Vue, svelte is the new and
cool kid on the block. I have to admit, the compile-to-plain-javascript
philosophy is nice, and what is especially cool is the fact that with
Rollup.js you can easily bundle a svelte
app into easy-to-embed component.
I wanted to make a simple embeddable Svelte component for a friend of mine,
that would be as simple as possible to include in a blog post, web site or
similar with just:
The script should ideally just put the component in the same place. Turns out
this is really easy with Svelte. Let's dive in!
Setting up Svelte
You may want to read more about
rollup-plugin-svelte and
Making an app from excellent
Svelte tutorial to get more familiar with the tools used here, as I'll only
cover the bare essentials.
First you need to install the necessary plugins. We'll start with Rollup and
install it globally so you can just use rollup command to do things. If
you want, you can also install rollup
locally.
I initially got an error saying something about imports and after a bit of
googling found out that my Ubuntu version of node was very old (node -v
outputted 8.x.x when 10+ was needed) – if you encounter the same issue,
upgrade to a newer node (nvm is a great too to
do this).
Next make a product directory and install svelte and rollup-plugin-svelte:
We'll go really barebones with this tutorial, just a simple heading and a
paragraph. Create a Svelte component Embed.svelte:
<script>
export let name; // from props
</script>
<h1>Hello, {name}!</h1>
<p>This component was brought to you by <a href="https://codeandlife.com/">Code
& Life</a>.</p>
Then we'll need a simple .js script to import that our mini-component and
inject it to the DOM of whatever page has included the resulting script.
Let's call this embed.js:
I wanted to gift some bitcoin to a friend, and came up with a fun idea of
writing them a poem with words making up an BIP-39 mnemonic word list.
Then they can easily type in the 12 words in Electrum and take control
of their wallet (and maybe transfer the amount to a wallet I don't have
access to :).
BIP-39 Fundamentals
Basic idea of BIP 39 is that there is a wordlist of 2048 words, so each word
choice encodes 11 bits (2^11 = 2048) of entropy. With 12 words, you have
12*11=132 bits, enough for 128 bits of of true entropy and a 4 bit checksum.
You can read all about it in the
BIP-39
itself.
Now only problem is, that the last word is not random, but must match
the top 4 bits of SHA256 checksum of the preceding 128 bits. So essentially
you can choose the 11 first words, and then try to see which choices of
12th word end up with a valid word list mnemonic.
One could manually type stuff into Electrum word list box, but trying 2048
options sounds pretty frustrating (on average, every 16th try will work).
So let's do it in Python!
Validating a BIP-39 word list in Python
First, grab the English wordlist — and yes BIP-39 is not the best way as it depends on the word list, but it is standard enough. Then we read
it in with Python:
import hashlib, binascii, sys
nums = {}
wordlist = []
with open('english.txt') as fin:
i = 0
for word in fin:
nums[word.strip()] = i
wordlist.append(word.strip())
i += 1
I got tired of the fact, that Philips Hue application does not seem to have
any easy way to set multiple lights to different colors (and possibly brightnesses)
at once. Thankfully, there is a great "REST API" to query light and set status!
Read on how to query your lights, set them, and do RBG to Philips Hue XY (or X, Y)
colorspace conversion with Python!
Connecting and configuring your Philips Hue for API access
This is a prerequisite step. Find out your Hue Brige's IP and create a user
(simple method of authentication). It's all covered in Get started.
Write down your IP and the username, and proceed
to activate your user and test it according to
instructions. Once you are done, you should be
able to also open the lights list in your
browser and see a lot of info:
https:///api//lights
Listing Your Connected Philips Hue Lights with Python
Alright, with the prerequisites done, let's do
a simple test with Python, and query that same
address parse the returned JSON, and pretty print
it. You'll need Python 3.10+ for this:
import urllib.request
import ssl, json, pprint
context = ssl._create_unverified_context()
def get_json(url):
"""Do a HTTP GET request and return response parsed as JSON."""
print(url)
req = urllib.request.Request(url=url, method='GET')
f = urllib.request.urlopen(req, context=context)
print(f.status, f.reason)
return json.loads(f.read())
# Replace these with your config
user = 'yourverylongusernamestring'
ip = '192.168.1.123'
data = get_json(f'https://{ip}/api/{user}/lights')
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(data)
for k in data: print(k, data[k]['name'])
A while ago I updated my site to
Eleventy.js. This improved
my blogging process considerably, as Markdown is quick to write,
and especially code samples are easy to copy-paste without any escaping.
I put all my posts into one Github repository. Using Visual Studio
Code, I get nice realtime preview, and once I'm
done, I just git commit, git push on my computer, and git pull on the
server, and regenerate the site with Eleventy.
Now only issue is that one usually finds 5-10 things to change after every
post, and while VS Code has great git support built in, even the simple update
process gets a bit tedious with commands being run on SSH side. So I started
wondering if I could use the Github
webhooks
to automate the regeneration. Turns out: YES.
Simple Script to Pull Markdown from Github and Regenerate
First component is of course a small shell script to automate the git pull and
regeneration. One could do a more elaborate one, but this worked for me server-side:
#!/bin/sh
cd ~/myblog_post # here are the .md files
git pull
cd ~/myblog_eleventy # here's the 11ty site generator
npx @11ty/eleventy --input=. --output=../apps/myblog_static # hosting dir
Node.js Mini-Server for Github Webhooks
Next, I needed to set up a web server that would get the HTTP POST from
Github whenever I push changes. Here your configuration will depend on
hosting you have, but Opalstack for example
has simple installation of a Node.js application. I usually disable the
automatic restarting (crontab -e etc.), use ./stop script and run my server manually for a while to see everything works, before restoring the crontab.
If you choose to forego Github webhook security mechanisms, the code is really
simple, but in that case, anyone knowing the addess of your server can flood
you with fake push requests. So let's take the high road and use this gist to
verify Github hooks! I chose to use Polka so I needed to modify
the headers part of the code just a bit:
const { exec } = require("child_process");
const polka = require('polka');
const { json } = require('body-parser');
const crypto = require('crypto')
const port = 12345;
const secret = 'ohreally :)';
const sigHeaderName = 'x-hub-signature-256';
const sigHashAlg = 'sha256';
// Middleware to verify Github "signed" POST request
function verifyPostData(req, res, next) {
console.log('Verifying signature', req.headers[sigHeaderName]);
if (!req.rawBody) {
console.log('Request body empty');
return next('Request body empty');
}
const sig = Buffer.from(req.headers[sigHeaderName] || '', 'utf8');
const hmac = crypto.createHmac(sigHashAlg, secret);
const digest = Buffer.from(sigHashAlg + '=' +
hmac.update(req.rawBody).digest('hex'), 'utf8');
if (sig.length !== digest.length || !crypto.timingSafeEqual(digest, sig)) {
console.log('Got request with invalid body digest');
return next(`Request body digest (${digest}) did not match
${sigHeaderName} (${sig})`);
}
console.log('Verification done.');
return next()
}
polka()
.use(json({ verify: (req, res, buf, encoding) => {
// Store raw body data in req rawBody variable
if(buf && buf.length) req.rawBody = buf.toString(encoding || 'utf8');
}
}))
.get('/', (req, res) => { res.end('Hello, polka!'); }) // just for testing
.post('/myblog', verifyPostData, (req, res) => {
console.log('Article repo updated, generating site...');
exec('~/blog_eleventy/gen.sh', (error, stdout, stderr) => {
if(error) console.log(`error: ${error.message}`);
if(stderr) console.log(`stderr: ${stderr}`);
console.log(`stdout: ${stdout}`);
});
res.end(`Hello, Github!`);
})
.listen(port, () => {
console.log(`> Running on localhost:${port}`);
});
For some reason, my particular configuration had the Github authorization
header in req.headers['x-hub-signature-256'] instead of the capitalized
X-Hub-Signature-256. Go figure.
In recent years, the use of graphics processing units (GPUs) has led to the adoption of methods like PBKDF2 (Password-Based Key Derivation Function 2) for secure password storage. PBKDF2 is a key derivation function that is designed to be computationally expensive in order to slow down dictionary attacks and other brute force attacks on passwords. With the increase in processing power that GPUs provide, PBKDF2 has become a popular choice for password storage.
As the development of processing power continues to advance, it has become necessary to increase the number of iterations used in PBKDF2 in order to maintain a high level of security. With more iterations, it becomes even more difficult for an attacker to crack a password using brute force methods.
Recently, I had an idea. What if it were possible to run PBKDF2 arbitrarily long and print out points that match certain criteria? This could potentially provide an even higher level of security for password storage, as the number of iterations could be increased to levels that would make brute force attacks infeasible. It's an idea worth exploring and I'm excited to see what the future holds for PBKDF2 and other password security measures.
Bitcoin difficulty
One of the key features of the Bitcoin network is its use of difficulty to scale the hardness of block signing based on the number of computers that are currently mining. In other words, as more computers join the network and begin trying to solve the cryptographic puzzles required to add new blocks to the blockchain, the difficulty of these puzzles increases in order to maintain a consistent rate of block creation. This ensures that the network remains secure and resistant to attacks, even as the number of miners grows over time.
The basic idea behind this technique is fairly simple: by requiring that a certain number of zeros be added to the block hash, the complexity of the puzzle increases in powers of two. Every hash is essentially
random, and modifying the hashed data by the tiniest bit results in a new hash. Every other hash ends in zero, and every other in one. With two zero bits, it's every 4th. To zero a full byte (8 bits) you already need 256 (2^8) tries. With three bytes, it's already close to 17 million.
Printing out PBKDF2 steps at deterministic points
Combining the two ideas is one way to deterministically create encryption keys of increasing difficulty:
I previously covered how to decode Nexa smart power plug remote control signals using Arduino Uno. The drawback of Arduino was the limited capture time and somewhat inaccurate timing information (when using a delay function instead of an actual hardware interrupt timer).
Another way to look at signals is an oscilloscope, and a soundcard can work as a "poor man's oscilloscope" in a pinch. You wire the signal to left/right channel (you could even wire two signals at the same time) and "measure" by recording the audio. It helps if ground level is shared between the soundcard and the signal source. In this case I achieved it pretty well by plugging the Arduino that still provides 3.3V voltage for the 433 MHz receiver chip to the same USB hub as the soundcard.
Another thing to consider is the signal level. Soundcard expects the voltage to be around 0.5V, whereas our receiver is happily pushing full 3.3V of VCC when the signal is high. This can be fixed with a voltage divider -- I wired the signal via a 4.7 kOhm resistor to the audio plug tip, and a 1 kOhm resistor continues to GND -- effectively dropping the voltage to less than a fifth of original.
The audio plug "sleeve" should be connected to GND as L/R channel voltages are relative to that. There was a 0.1V difference in voltage between soundcard sleeve and Arduino GND so I decided to put a 1 kOhm resistor also here to avoid too much current flowing through a "ground loop".
Note that I'm using a SparkFun breakout for the plug that makes connecting the plug to a breadboard quite easy. If you need to wire it directly to the connector (signal to "tip" and ground to "sleeve"), refer to diagram here: https://en.wikipedia.org/wiki/Phone_connector_(audio). A word of caution: You can break stuff if you wire it incorrectly or provide too high voltage to some parts, so be careful and proceed at your own risk!
You can see the circuit in the picture above. Note that due to receiver needing GND in two places, I've been able to connect the sleeve to another GND point (rightmost resistor) than the other 1 kOhm resistor that is part of the voltage divider (leftmost resistor)
Trying it out with Audacity
Once you have power to the receiver, and 1 kOhm resistors to sleeve and tip and signal through a 4.7 kOhm (anything between that and 22 kOhm works pretty well with 16 bits for our ON/OFF purposes), you can start a recording software like Audacity to capture some signals. Here is a sample recording where I've pressed the remote a couple of times:
As you can see, our signal is one-sided (audio signals should be oscillating around GND, where as our is between GND and +0.5V) which causes the signal to waver around a bit. If you want a nicer signal you can build a somewhat more elaborate circuit but this should do for our purposes.
By the way, you can use ctrl-A to select all of the recorded audio and use the "Amplify" effect (with default settings) maximize signal to available audio headroom. Makes looking at the signals a little easier. I've done that before the captures below. Another issue becomes apparent when we zoom in a bit closer:
Due to automatic gain in the receiver chip (or maybe some other anomaly), the receiver consistently captures some "garbage signal" some 200 ms after the "official" Nexa signal we got a glimpse of in the [previous part of this series]. It is not pure noise but seems to contain some other signal, probably coming somewhere else in the building but at a much lower power level -- the receiver records this as well, but blocks it for a while once it gets the more powerful Nexa signal.
To analyze the Nexa signal, I suggest deleting other parts of audio capture than the actual signals. I actually tore open the Nexa remote and measured the signal straight from the antenna to make sure this recurring "tail" is not coming from the remote. :D
Below you can see a zoom-in of the signal at various levels of magnification. Note that I'm not zooming in on the first signal that has the "spike" before the actual signal starts.
As you can see, the 44.1 kHz signal has enough resolution to deduce the signal protocol just with Audacity. But countint the individual samples from HIGH and LOW segments to get an average length is pretty tedious. If only we could do it programmatically...
Using Python to analyze the recorded signal
I made a handy Python script to analyze the recorded signal. Basic procedure is: