Skip to content

Commit

Permalink
Refactored project tree, implemented player repo logic and solution u…
Browse files Browse the repository at this point in the history
…pdates
  • Loading branch information
loicortola committed Mar 17, 2019
1 parent f631e13 commit 225a9b7
Show file tree
Hide file tree
Showing 124 changed files with 447 additions and 188 deletions.
Binary file removed bin/constant.pyc
Binary file not shown.
18 changes: 0 additions & 18 deletions bin/setup.py

This file was deleted.

63 changes: 0 additions & 63 deletions boilerplate/chapter1/tsconfig.json

This file was deleted.

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion bin/constant.py → install/scripts/constant.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,5 @@
SAVE_LORA_API_IMAGE = "resourcepool/save-lora-appserver"
SAVE_LORA_WEB_IMAGE = "resourcepool/save-lora-website"

# Client Git Repo
# Public Git Repo for Players
GIT_REPO = "https://github.com/resourcepool/save-lora.git"
6 changes: 6 additions & 0 deletions install/scripts/deploy_player_repo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env python3
from gh import playerrepo
import os
os.chdir(os.path.dirname(os.path.realpath(__file__)))
playerrepo.init_with_resources()
playerrepo.commit_and_push_force()
12 changes: 12 additions & 0 deletions install/scripts/deploy_solution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env python3
from gh import playerrepo
import os
import sys
os.chdir(os.path.dirname(os.path.realpath(__file__)))
playerrepo.clone_from_remote()

if (len(sys.argv) != 3):
print("Usage: python3 deploy_solution.py [chapter] [step]")
print("Example: python3 deploy_solution.py chapter1 step-2")
exit(1)
playerrepo.deploy_solution(sys.argv[1], sys.argv[2])
36 changes: 36 additions & 0 deletions install/scripts/gh/playerrepo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import constant
import tempfile
import shutil
import os
from git import Repo

tmpdir = tempfile.mkdtemp(suffix='player')
repodir = tmpdir + "/repo"

def init_with_resources():
print("Copying resources to " + repodir)
shutil.copytree("../../resources/boilerplate", repodir, ignore=shutil.ignore_patterns("node_modules"))
shutil.copytree("../../resources/course", repodir + "/course")


def commit_and_push_force():
repo = Repo.init(repodir)
origin = repo.create_remote('origin', constant.GIT_REPO)
assert origin.exists()
repo.git.add("--all")
repo.git.commit(message="Initial Commit")
repo.git.push("-f", "origin", "master")


def clone_from_remote():
repo = Repo.clone_from(constant.GIT_REPO, repodir)
assert repo.__class__ is Repo


def deploy_solution(chapter, step):
print("Copying solution from " + chapter + " / " + step)
shutil.copytree("../../resources/solution/" + chapter + "/" + step, repodir + "/solution/" + chapter + "/" + step, ignore=shutil.ignore_patterns("node_modules"))
repo = Repo(repodir)
repo.git.add("--all")
repo.git.commit(message="Added solution for " + chapter + " - " + step)
repo.git.push("origin", "master")
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
16 changes: 16 additions & 0 deletions install/scripts/setup_ansible_vars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/usr/bin/env python3

import servers
import utils
import constant
import os
os.chdir(os.path.dirname(os.path.realpath(__file__)))

groupvars = []
servers.mqtt.setup(groupvars)
servers.savelora.setup(groupvars)
servers.saveloraweb.setup(groupvars)
servers.loraserver.setup(groupvars)
servers.dockers.setup(groupvars)

utils.replace("../../" + constant.ANSIBLE_GROUPVARS_FILE, constant.ANSIBLE_BEGIN_TOKEN, constant.ANSIBLE_END_TOKEN, groupvars)
File renamed without changes.
6 changes: 6 additions & 0 deletions resources/boilerplate/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
__snapshots__
dist
node_modules
.DS_Store
*.iml
.idea
22 changes: 22 additions & 0 deletions resources/boilerplate/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Save-LoRa

Welcome to the handson workshop **Save-LoRa**.

Before you start, please read the following lines carefully.

## Requirements
* Compatible with Windows 8+ / Mac OSX / Linux
* 1 USB Port available
* Internet connection
* Requires Node 8+

## Setup
* Clone the current repository in your workspace
* Browse to chapter1/ and Run `npm install`. This might take a while.
* Browse to chapter2/ and Run `npm install`. This might take a while.

## Game guide

The game step-by-step guide is available here: [https://resourcepool.github.io/save-lora](https://resourcepool.github.io/save-lora)

That's it! See you soon!
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @type {{}}
*/
const CHANGEME = {
clientId: 'hacker-1234',
clientId: 'change-me',
deviceEUI: '13:37:00:00:FF:FF:FF:FF'
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ let init = () => {
// TODO Step 1: Connect to the city's remote MQTT Broker
// Using the provided MQTT client, connect to the remote MQTT broker (cf README.md)
// Don't forget to manually set your clientId, otherwise your step wont be validated!
// Those idiots forgot to put any security on it... Noobs!
// Those idiots gave away their credentials so easily... Noobs!
// MQTT Client documentation => https://github.com/mqttjs/MQTT.js
// You want to listen to all incoming messages... Did I hear the word "Wildcard"?
};
Expand Down Expand Up @@ -61,7 +61,7 @@ let onMessage = async (topic, message) => {
// (It's like a new computer trying to go join a nazily-secured enterprise network
// and your sysadmin needs to whitelist your computer's mac address).
// Therefore we want to interact with the LoraServer API.
// Thanks to your awesome friend John Doe, you already have a async-client available in api/api.js
// Thanks to your awesome Anonymous friend, you already have a async-client available in api/api.js
if (!await api.deviceExists(decodedJoinRequest.devEUI)) {
// TODO Step 3.1: register your friend's device remotely.
}
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ A JoinRequest contains:
The good thing about JoinRequests is that they are **not** Encrypted.
That means we can easily decode them from the MQTT broker packets!

To understand how to spot a Join Request, you need to read the binary protocol used to encode the payload. You should read your LoRaWAN 101 course... [Here's a link if you don't have it](/course/lorawan-101-course.md).
To understand how to spot a Join Request, you need to read the binary protocol used to encode the payload. You should read your LoRaWAN 101 course... [Here's a link if you don't have it](/resources/course/lorawan-101-course.md).

**How to spot a JoinRequest:**
A join request can be recognized by the following:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ OTAA requires three parameters :
* an AppEUI (this one needs to be changed)
* an AppKey (this one needs to be changed)

All Modems are controlled using what we call AT Commands. Fortunately, you also had printed the [documentation of your LoRa Node device](/course/lora-node-guide.pdf)!
All Modems are controlled using what we call AT Commands. Fortunately, you also had printed the [documentation of your LoRa Node device](/resources/course/lora-node-guide.pdf)!

Remember what Trinity said in her text: She wants you to change all settings to "42".

Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"description": "MQTT client which monitors and registers LoRa devices in the Save Lora hack game",
"scripts": {
"start": "node ./src/index.js",
"test": "jest src"
"test": "./node_modules/jest/bin/jest.js src"
},
"author": "Resourcepool",
"license": "Apache-2.0",
Expand Down
File renamed without changes.
File renamed without changes.
93 changes: 93 additions & 0 deletions resources/solution/chapter1/complete/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
const api = require('./api/api');
const utils = require('./utils');
const mqtt = require('mqtt');
const conf = require('./conf');
const reviewService = require('./progress/review-service');

const Logger = require('./log/logger');

const JoinRequestPacketDecoder = require('./decoder/JoinRequestPacketDecoder');

const gatewayRxTopicRegex = new RegExp("^gateway/([0-9a-fA-F]+)/rx$");

const validAppEUI = utils.hexStringToBytes(conf.user.appEUI);
const validMockAppEUI = utils.hexStringToBytes(conf.user.mockAppEUI);
const deviceEUI = utils.hexStringToBytes(conf.user.deviceEUI);
const deviceNetworkKey = utils.normalizeHexString(conf.user.nwkKey);

const logger = Logger.child({service: 'index'});
let client;

let init = () => {
reviewService.init();
client = mqtt.connect(conf.mqtt.host, {username: conf.mqtt.username, password: conf.mqtt.password, clientId: conf.user.clientId});
client.on('connect', () => {
client.subscribe('#', (err) => {
if (err) {
process.exit(1);
}
});
});
client.on("message", onMessage);

};

/**
* Step 2
* @param topic
* @param message
*/
let onMessage = async (topic, message) => {
if (!gatewayRxTopicRegex.test(topic)) {
return;
}

let msgDecoder = new JoinRequestPacketDecoder(topic, message);
if (!msgDecoder.isSupported()) {
return;
}

logger.debug("Join Request identified");
let decodedJoinRequest = msgDecoder.decode();
logger.debug("Decoded:" + JSON.stringify(decodedJoinRequest));

// Congratulations, you are decoding all the join requests of the LoRa network.
// However, we want to be smart hackers and only activate your friend's device on the specific APP_EUI
if (isValidAppEUI(decodedJoinRequest.appEUI) && isRightDeviceEUI(decodedJoinRequest.devEUI)) {
logger.debug("AppEUI and DevEUI are valid. Will register device");
if (!await api.deviceExists(decodedJoinRequest.devEUI)) {
await api.createDevice({
devEUI: decodedJoinRequest.devEUI,
applicationID: conf.loRaServer.loRaApplicationId,
deviceProfileID: conf.loRaServer.rak811DevProfileId,
name: conf.user.clientId,
description: '4242'
});
}
if (!await api.deviceNwkKeyExists(decodedJoinRequest.devEUI)) {
await api.setDeviceNwkKey(decodedJoinRequest.devEUI, deviceNetworkKey);
}
logger.debug("Device registered successfully");
}
};

/**
* Check whether the AppEUI of the intercepted message is the one we want to work on
* @param msgAppEUI string|Uint8Array
* @returns {boolean}
*/
let isValidAppEUI = (msgAppEUI) => {
return utils.arraysEqual((typeof msgAppEUI === 'string') ? utils.hexStringToBytes(msgAppEUI) : msgAppEUI, validAppEUI) || utils.arraysEqual((typeof msgAppEUI === 'string') ? utils.hexStringToBytes(msgAppEUI) : msgAppEUI, validMockAppEUI);
};

/**
* Check whether the DeviceEUI equals the team's device.
* If you don't implement this right, you might give a head start to all your competitors!
* @param devEUI string|Uint8Array
* @returns {boolean}
*/
let isRightDeviceEUI = (devEUI) => {
return utils.arraysEqual((typeof devEUI === 'string') ? utils.hexStringToBytes(devEUI) : devEUI, deviceEUI);
};

init();
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,6 @@ let client;

let init = () => {
reviewService.init();
// TODO Step 1: Connect to the city's remote MQTT Broker
// Using the provided MQTT client, connect to the remote MQTT broker (cf README.md)
// Don't forget to manually set your clientId, otherwise your step wont be validated!
// Those idiots forgot to put any security on it... Noobs!
// MQTT Client documentation => https://github.com/mqttjs/MQTT.js
// You want to listen to all incoming messages... Did I hear the word "Wildcard"?
client = mqtt.connect(conf.mqtt.host, {username: conf.mqtt.username, password: conf.mqtt.password, clientId: conf.user.clientId});
client.on('connect', () => {
client.subscribe('#', (err) => {
Expand All @@ -35,7 +29,6 @@ let init = () => {
});
});
client.on("message", onMessage);

};

/**
Expand Down Expand Up @@ -71,20 +64,12 @@ let onMessage = async (topic, message) => {
// (It's like a new computer trying to go join a nazily-secured enterprise network
// and your sysadmin needs to whitelist your computer's mac address).
// Therefore we want to interact with the LoraServer API.
// Thanks to your awesome friend John Doe, you already have a async-client available in api/api.js
// Thanks to your awesome Anonymous friend, you already have a async-client available in api/api.js
if (!await api.deviceExists(decodedJoinRequest.devEUI)) {
// TODO Step 3.1: register your friend's device remotely.
await api.createDevice({
devEUI: decodedJoinRequest.devEUI,
applicationID: conf.loRaServer.loRaApplicationId,
deviceProfileID: conf.loRaServer.rak811DevProfileId,
name: conf.user.clientId,
description: '4242'
});
}
if (!await api.deviceNwkKeyExists(decodedJoinRequest.devEUI)) {
// TODO Step 3.2: set the device Network key (NwkKey).
await api.setDeviceNwkKey(decodedJoinRequest.devEUI, utils.normalizeHexString(conf.user.nwkKey));
}
logger.debug("Device registered successfully");
}
Expand Down
Loading

0 comments on commit 225a9b7

Please sign in to comment.