Use Apple HomeKit to control cheap 433 MHz devices

homebridge-telldus is a plugin for homebridge which allows you to control cheap 433MHz devices like wireless light switches and dimmers from Apple’s Home integration. This is done through Telldus Live, which provides a free service and API integration for people who bought their devices like TellStick Net and TellStick ZNet Lite. It provides a very cheap way to control your house with Siri and Apple Home.

See compatible hardware here:
https://old.telldus.com/products/compability

v1 of the homebridge-telldus plugin now also supports local communiation directly with devices that support this, like the TellStick ZNet Lite.

For instructions on how to set up the system, see:
https://github.com/jchnlemon/homebridge-telldus

Hidden hot spring behind Seljavallalaug in Iceland

Seljavallalaug pool

Most people have heard about the Seljavallalaug pool. Its temperature is lukewarm and some people advise against swimming there because of bacteria/algae in the pool. However if you go a couple hundred meters up the river, you will find a pretty cool makeshift hot pool right next to the river where you can do cold dipping in the glacial river followed by 42C of pleasure.

Hidden hot spring

GPS coordinates đź—ş 63.567221, -19.606444

Migrate WordPress URLs to nginx (hexo)

I have migrated my blog from WordPress to hexo, but the old URLs need to be permanently redirected.
I’m using NGINX as my web server, so I set up some rules for redirecting the old posts to the new URLs. It’s a bit tricky because WordPress used query string param for identifying the page, but it can be sorted out using if and the NGINX $arg_ variable. In order to generate these rules, I wrote a simple node script that runs through the exported Markdown files from WordPress. Markdown files were exported using Jekyll Exporter plugin.)

index.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const fm = require('front-matter');
const fs = require('fs');
const moment = require('moment');
const path = require('path');
const dir = 'blog.mifi.no/source/_posts';
const baseUrl = 'https://blog.mifi.no/';
const files = fs.readdirSync(dir);
files.forEach((file) => {
var doc = fm(fs.readFileSync(path.join(dir, file), 'utf8'));
const id = doc.attributes['id'];
if (!id) return;
const date = moment(doc.attributes.date).utc()
const url = `${baseUrl}${date.format('YYYY/MM/DD')}/${file.split('.md')[0]}`;
console.log(`if ($arg_p = ${id}) { return 301 ${url}; }`);
});

1
2
3
npm i front-matter
npm i moment
node .

Then insert output from the script to the nginx server block of the old blog:

1
2
3
4
5
6
location /blog {
<output from index.js cmd>
# default redirect
return 301 https://blog.mifi.no/;
}

Now that all pages have been redirected 301 to their new paths, a simple comment export from WordPress and import to Disqus was automatically able to crawl the old URL 301 redirects and update the URL of the Disqus comments. (Using the crawl migration tool in Disqus admin.)

Reverse engineering DNB VIPPS API by injecting Charles cert as pinned SSL certificate

charles

The VIPPS app is using API SSL certificate pinning to prevent MITM attacks, and the pinned certificate(s) is stored in the APK itself, so it can easily be replaced by our own generated Charles certificate. This allows sniffing the data going from the app to VIPPS servers.

Instructions

First download the APK from somewhere (google it)

Debuild APK
apktool d no.dnb.vipps-1.6.5.apk

Export Charles MITM SSL certificate by going to Help -> SSL Proxying -> Save Charles Root Certificate

Inject Charles certificate into app
cp charles-ssl-proxying-certificate.cer no.dnb.vipps-1.6.5.apk.out/res/raw/prod_priority_1.cer

Put APK back together
apktool b no.dnb.vipps-1.6.5.apk.out -o vipps-modified.apk

Generate debug keystore for signing the new app
echo y | keytool -genkey -v -keystore debug.keystore -storepass android -alias androiddebugkey -keypass android -keyalg RSA -keysize 2048 -validity 10000 -dname "cn=Mark Jones, ou=JavaSoft, o=Sun, c=US"

Sign app with keystore
apksigner sign --ks debug.keystore --out vipps-modified-signed.apk vipps-modified.apk

Enter pw android

Verify signing
apksigner verify vipps-modified-signed.apk

Install new APK to device
adb install vipps-modified-signed.apk

Now just start Charles with SSL proxying enabled and set Charles (your computer’s IP) as the proxy under WIFI settings on the Android device.

Going further - decompiling

brew install dex2jar

d2j-dex2jar -f -o vipps.jar no.dnb.vipps-1.6.5.apk

Use one of the following GUI tools for decompiling and looking at the code:

None of them are perfect, and some code seems to fail decompiling in both.

AWS Cogntio: Prevent email from being sent when email changed

When calling adminUpdateUserAttributes to change email address of a user in Cognito User Pools, the attribute email_verified will be set to false, and an email will be sent out to the user with a verification code.
If you want to disable this logic and prevent the email from being sent out, include email_verified=true in the update attributes request, like so:

1
2
3
4
5
6
7
8
9
10
11
12
{
"UserAttributes": [
{
"Name": "email",
"Value": "new-email@example.com"
},
{
"Name": "email_verified",
"Value": "true"
}
]
}

LosslessCut

I needed a tool for quickly trimming recorded videos, so I built my first Electron app, check it out:
https://mifi.github.io/lossless-cut/

Download links:
https://github.com/mifi/lossless-cut/releases

It is a cross platform simple video editor for lossless trimming / cutting of videos using ffmpeg and Electron. Great for rough processing of large video files taken from a video camera, drone, etc. Lets you quickly get rid of the useless parts. It doesn’t do any decoding / encoding and is therefore very fast and has no quality loss. Also allows for taking JPEG snapshots of the video at the selected time.

Extract GPS data from "Tracker" iOS app to GPS

Quick script for extracting gps data from the Tracker GPS app

First export data from app com.eofster.tracker using something like iPhone Backup Extractor (http://supercrazyawesome.com/)

1
2
3
4
5
6
mkdir tracker-extract && cd tracker-extract
npm install csvtojson
npm install gps-to-gpx
(cd 'com.eofster.tracker/Library/Application Support/com.eofster.tracker' && sqlite3 -header -csv Tracker.sqlite "select * from ZTRACKPOINT order by ZTIMESTAMP;" > out.csv)

Create index.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var Converter = require("csvtojson").Converter;
var converter = new Converter({});
const createGpx = require('gps-to-gpx').default;
//end_parsed will be emitted once parsing finished
converter.on("end_parsed", function (jsonArray) {
//console.log(jsonArray);
const converted = jsonArray.map(pos => {
return {
latitude: pos.ZLATITUDE,
longitude: pos.ZLONGITUDE,
elevation: pos.ZALTITUDE,
time: new Date((pos.ZTIMESTAMP+978307200)*1000).toISOString()
};
});
const gpx = createGpx(converted, {
activityName: 'tur',
startTime: converted[0].time,
});
console.log(gpx);
});
//read from file
require("fs").createReadStream("out.csv").pipe(converter);

Run:

1
node . > out.gpx