Add AEAD
This commit is contained in:
parent
1b4c4add09
commit
a6f0f8c72a
@ -5,4 +5,5 @@ go 1.15
|
|||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.7.4
|
github.com/gin-gonic/gin v1.7.4
|
||||||
go.mongodb.org/mongo-driver v1.7.2
|
go.mongodb.org/mongo-driver v1.7.2
|
||||||
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
|
||||||
)
|
)
|
||||||
|
@ -19,6 +19,10 @@ func main() {
|
|||||||
func initializeRoutes(r *gin.Engine) {
|
func initializeRoutes(r *gin.Engine) {
|
||||||
r.POST("/data", src.CreateData)
|
r.POST("/data", src.CreateData)
|
||||||
r.PUT("/data/:id", src.CreateEnvironmentData)
|
r.PUT("/data/:id", src.CreateEnvironmentData)
|
||||||
|
r.Use(src.AEADHandler)
|
||||||
|
{
|
||||||
|
r.PUT("/data/authed/:id", src.CreateEnvironmentData)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getPort() string {
|
func getPort() string {
|
||||||
|
@ -2,15 +2,22 @@ package src
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"encoding/base64"
|
||||||
|
|
||||||
|
"go.mongodb.org/mongo-driver/bson"
|
||||||
"go.mongodb.org/mongo-driver/mongo"
|
"go.mongodb.org/mongo-driver/mongo"
|
||||||
"go.mongodb.org/mongo-driver/mongo/options"
|
"go.mongodb.org/mongo-driver/mongo/options"
|
||||||
"go.mongodb.org/mongo-driver/mongo/readpref"
|
"go.mongodb.org/mongo-driver/mongo/readpref"
|
||||||
|
"golang.org/x/crypto/blake2s"
|
||||||
)
|
)
|
||||||
|
|
||||||
const uri = "mongodb://192.168.0.159:27017"
|
const uri = "mongodb://192.168.0.159:27017"
|
||||||
|
const salt = "ENVIRONMENT"
|
||||||
|
|
||||||
var dbCollection *mongo.Collection
|
var dbCollection *mongo.Collection
|
||||||
|
var dbDevices *mongo.Collection
|
||||||
var mongoClient *mongo.Client
|
var mongoClient *mongo.Client
|
||||||
|
|
||||||
func DbConnect() {
|
func DbConnect() {
|
||||||
@ -23,8 +30,38 @@ func DbConnect() {
|
|||||||
if err := mongoClient.Ping(context.TODO(), readpref.Primary()); err != nil {
|
if err := mongoClient.Ping(context.TODO(), readpref.Primary()); err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
|
db := mongoClient.Database("Environment")
|
||||||
|
dbCollection = db.Collection("Main")
|
||||||
|
dbDevices = db.Collection("Devices")
|
||||||
|
}
|
||||||
|
|
||||||
dbCollection = mongoClient.Database("Environment").Collection("Main")
|
func GetDeviceKey(api uint64) ([]byte, error) {
|
||||||
|
apiSigned := int64(api)
|
||||||
|
filter := bson.D{{"ApiID", apiSigned}}
|
||||||
|
var result bson.M
|
||||||
|
err := dbDevices.FindOne(context.TODO(), filter).Decode(&result)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
key, err := DeriveKey(result["Passcode"].(string))
|
||||||
|
fmt.Printf(base64.StdEncoding.EncodeToString(key))
|
||||||
|
// We should cache this!
|
||||||
|
return key, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeriveKey(passcode string) ([]byte, error) {
|
||||||
|
|
||||||
|
hash, err := blake2s.New256(nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
hash.Write([]byte(salt))
|
||||||
|
hash.Write([]byte(passcode))
|
||||||
|
|
||||||
|
fmt.Printf("SALT %s PASS %s\n", salt, passcode)
|
||||||
|
|
||||||
|
return hash.Sum(nil), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func DbDisconnect() {
|
func DbDisconnect() {
|
||||||
|
58
Api/src/middleware.go
Normal file
58
Api/src/middleware.go
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
package src
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"golang.org/x/crypto/chacha20poly1305"
|
||||||
|
)
|
||||||
|
|
||||||
|
const ivSize = 12
|
||||||
|
const DecryptedData = "DecryptedData"
|
||||||
|
|
||||||
|
func AEADHandler(c *gin.Context) {
|
||||||
|
// get id
|
||||||
|
uintID, err := strconv.ParseUint(c.Param("id"), 10, 64)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERR %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusUnauthorized)
|
||||||
|
} else {
|
||||||
|
// get key
|
||||||
|
passcode, err := GetDeviceKey(uintID)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERR %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusNotFound)
|
||||||
|
} else {
|
||||||
|
// get content
|
||||||
|
data, err := c.GetRawData()
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERR %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusBadRequest)
|
||||||
|
} else {
|
||||||
|
// decrypt
|
||||||
|
iv, ciphertext := data[:ivSize], data[ivSize:]
|
||||||
|
aead, err := chacha20poly1305.New(passcode)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERR %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusInternalServerError)
|
||||||
|
} else {
|
||||||
|
fmt.Printf("iv: %s cypher: %s", base64.StdEncoding.EncodeToString(iv), base64.StdEncoding.EncodeToString(ciphertext))
|
||||||
|
plaintext, err := aead.Open(nil, iv, ciphertext, nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
fmt.Printf("ERR %s", err.Error())
|
||||||
|
c.AbortWithStatus(http.StatusBadRequest)
|
||||||
|
} else {
|
||||||
|
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(plaintext))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -3,6 +3,7 @@
|
|||||||
#include <Ticker.h>
|
#include <Ticker.h>
|
||||||
#include <U8g2lib.h>
|
#include <U8g2lib.h>
|
||||||
#include <ESP8266HTTPClient.h>
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#include "byte_buffer.h"
|
||||||
|
|
||||||
//scl D1
|
//scl D1
|
||||||
//sda D2
|
//sda D2
|
||||||
@ -27,8 +28,15 @@ float humidity = 0;
|
|||||||
#define TEMP "Temperature: "
|
#define TEMP "Temperature: "
|
||||||
#define HUMID "Humidity: "
|
#define HUMID "Humidity: "
|
||||||
|
|
||||||
|
#define DERIVATION_HASH_SIZE 32
|
||||||
|
static constexpr const char *DERIVATION_SALT = "ENVIRONMENT";
|
||||||
|
|
||||||
void UpdateEnvironment();
|
void UpdateEnvironment();
|
||||||
|
|
||||||
void PostEnvironment();
|
void PostEnvironment();
|
||||||
|
|
||||||
void InitializeWifi();
|
void InitializeWifi();
|
||||||
|
|
||||||
|
utils::byte_buffer Encrypt(std::string data);
|
||||||
|
|
||||||
|
void DeriveKey();
|
19
ESP-Temp-Humidity/include/settings.h
Normal file
19
ESP-Temp-Humidity/include/settings.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Environment
|
||||||
|
{
|
||||||
|
class Settings
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
/* data */
|
||||||
|
public:
|
||||||
|
uint64_t apiID;
|
||||||
|
|
||||||
|
std::string endpoint;
|
||||||
|
|
||||||
|
std::string passcode;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
@ -26,7 +26,7 @@ class setup_server
|
|||||||
|
|
||||||
bool serverConnection;
|
bool serverConnection;
|
||||||
|
|
||||||
uint8_t connect_to_ap(const std::string ssid, const std::string password);
|
uint8_t connect_to_ap(const std::string &ssid, const std::string &password);
|
||||||
|
|
||||||
void root_callback();
|
void root_callback();
|
||||||
|
|
||||||
|
200
ESP-Temp-Humidity/lib/utils/byte_buffer.cpp
Normal file
200
ESP-Temp-Humidity/lib/utils/byte_buffer.cpp
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
#include <byte_buffer.h>
|
||||||
|
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cstring>
|
||||||
|
#include <osapi.h>
|
||||||
|
#include <libb64/cdecode.h>
|
||||||
|
#include <libb64/cencode.h>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
byte_buffer::byte_buffer(uint_fast16_t length)
|
||||||
|
: _length(length)
|
||||||
|
{
|
||||||
|
// +1 to allow this to be safely printed as a char
|
||||||
|
_buffer = reinterpret_cast<unsigned char *>(std::calloc(length + 1, sizeof(unsigned char)));
|
||||||
|
}
|
||||||
|
|
||||||
|
byte_buffer::~byte_buffer()
|
||||||
|
{
|
||||||
|
clear_buffer();
|
||||||
|
std::free(_buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool byte_buffer::is_valid()
|
||||||
|
{
|
||||||
|
return _buffer != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char *byte_buffer::get_ptr()
|
||||||
|
{
|
||||||
|
if (is_valid())
|
||||||
|
{
|
||||||
|
return _buffer;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get the length of the buffer.
|
||||||
|
//
|
||||||
|
// Returns: The length of the buffer, or 0 if the buffer is invalid.
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
const uint_fast16_t byte_buffer::get_length()
|
||||||
|
{
|
||||||
|
if (is_valid())
|
||||||
|
{
|
||||||
|
return _length;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Get a pointer to a location in the buffer, length is updated to show the length
|
||||||
|
// available in that buffer
|
||||||
|
//
|
||||||
|
// index: The location to get a pointer to.
|
||||||
|
// length: The length of the data you expect to access from this pointer.
|
||||||
|
//
|
||||||
|
// Returns: A ptr to the buffer, or nullptr if reading that much data would cause
|
||||||
|
// an overflow
|
||||||
|
/////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
unsigned char *byte_buffer::get_ptr(const uint_fast16_t index, uint_fast16_t &length)
|
||||||
|
{
|
||||||
|
unsigned char *ret = nullptr;
|
||||||
|
|
||||||
|
if (is_valid() && _length > index)
|
||||||
|
{
|
||||||
|
length = _length - index;
|
||||||
|
ret = &_buffer[index];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
length = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy data into this buffer. The index value is updated to the index of the next point in the buffer
|
||||||
|
const bool byte_buffer::copy_from(const void *const sourceBuffer, uint_fast16_t &index, const uint_fast16_t &length)
|
||||||
|
{
|
||||||
|
auto ret = false;
|
||||||
|
if (is_valid() &&
|
||||||
|
sourceBuffer != nullptr &&
|
||||||
|
(index + length) <= _length)
|
||||||
|
{
|
||||||
|
std::memcpy(_buffer + index, sourceBuffer, length);
|
||||||
|
index += length;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Copy data out of this buffer. The index value is updated to the index of the next point in the buffer
|
||||||
|
const bool byte_buffer::copy_to(void *destinationBuffer, uint_fast16_t &index, const uint_fast16_t &length)
|
||||||
|
{
|
||||||
|
auto ret = false;
|
||||||
|
if (is_valid() &&
|
||||||
|
destinationBuffer != nullptr &&
|
||||||
|
(index + length) < _length)
|
||||||
|
{
|
||||||
|
std::memcpy(destinationBuffer, _buffer + index, length);
|
||||||
|
index += length;
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const bool byte_buffer::clone(byte_buffer &bufferToClone)
|
||||||
|
{
|
||||||
|
auto ret = false;
|
||||||
|
if (is_valid() &&
|
||||||
|
bufferToClone.is_valid() &&
|
||||||
|
bufferToClone.get_length() <= _length)
|
||||||
|
{
|
||||||
|
std::memcpy(bufferToClone.get_ptr(), 0, bufferToClone.get_length());
|
||||||
|
ret = true;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
const void byte_buffer::clear_buffer()
|
||||||
|
{
|
||||||
|
if (is_valid())
|
||||||
|
{
|
||||||
|
std::fill(_buffer, _buffer + _length, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const void byte_buffer::fill_random()
|
||||||
|
{
|
||||||
|
if (is_valid())
|
||||||
|
{
|
||||||
|
os_get_random(_buffer, _length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the size of the data stored
|
||||||
|
const uint_fast16_t byte_buffer::load_base64(std::string base64Data)
|
||||||
|
{
|
||||||
|
auto read = 0u;
|
||||||
|
|
||||||
|
if (is_valid() && _length >= base64_decode_expected_len(base64Data.length()))
|
||||||
|
{
|
||||||
|
base64_decodestate state;
|
||||||
|
base64_init_decodestate(&state);
|
||||||
|
read = base64_decode_block(base64Data.c_str(), base64Data.length(), reinterpret_cast<char *>(_buffer), &state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
|
||||||
|
//// Get a base64 encoded string of this buffer.
|
||||||
|
const std::string byte_buffer::get_base64()
|
||||||
|
{
|
||||||
|
if (!is_valid())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
auto b64String = std::string("");
|
||||||
|
auto size = base64_encode_expected_len_nonewlines(_length) + 1;
|
||||||
|
auto buffer = reinterpret_cast<char *>(std::calloc(size, 1));
|
||||||
|
if (buffer != nullptr)
|
||||||
|
{
|
||||||
|
|
||||||
|
base64_encodestate state;
|
||||||
|
base64_init_encodestate_nonewlines(&state);
|
||||||
|
|
||||||
|
auto encoded = base64_encode_block(reinterpret_cast<const char *>(_buffer), _length, buffer, &state);
|
||||||
|
encoded = base64_encode_blockend(buffer + encoded, &state);
|
||||||
|
|
||||||
|
b64String = std::string(buffer);
|
||||||
|
std::free(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
return b64String;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string byte_buffer::to_string()
|
||||||
|
{
|
||||||
|
if (!is_valid())
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure that extra byte really is null!
|
||||||
|
_buffer[_length] = '\0';
|
||||||
|
return std::string(reinterpret_cast<char *>(_buffer));
|
||||||
|
}
|
||||||
|
} // namespace Control_System
|
38
ESP-Temp-Humidity/lib/utils/byte_buffer.h
Normal file
38
ESP-Temp-Humidity/lib/utils/byte_buffer.h
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace utils
|
||||||
|
{
|
||||||
|
class byte_buffer
|
||||||
|
{
|
||||||
|
|
||||||
|
public:
|
||||||
|
byte_buffer(uint_fast16_t length);
|
||||||
|
~byte_buffer();
|
||||||
|
|
||||||
|
const bool is_valid();
|
||||||
|
|
||||||
|
unsigned char *get_ptr();
|
||||||
|
const uint_fast16_t get_length();
|
||||||
|
|
||||||
|
unsigned char *get_ptr(const uint_fast16_t index, uint_fast16_t &length);
|
||||||
|
|
||||||
|
const bool copy_to(void *destinationBuffer, uint_fast16_t &index, const uint_fast16_t &length);
|
||||||
|
const bool copy_from(const void *const sourceBuffer, uint_fast16_t &index, const uint_fast16_t &length);
|
||||||
|
|
||||||
|
const bool clone(byte_buffer &bufferToClone);
|
||||||
|
|
||||||
|
const void clear_buffer();
|
||||||
|
const void fill_random();
|
||||||
|
|
||||||
|
const uint_fast16_t load_base64(std::string base64Data);
|
||||||
|
const std::string get_base64();
|
||||||
|
const std::string to_string();
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned char *_buffer;
|
||||||
|
const uint_fast16_t _length;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Control_System
|
@ -15,3 +15,4 @@ framework = arduino
|
|||||||
lib_deps =
|
lib_deps =
|
||||||
olikraus/U8g2@^2.28.8
|
olikraus/U8g2@^2.28.8
|
||||||
finitespace/BME280@^3.0.0
|
finitespace/BME280@^3.0.0
|
||||||
|
rweather/Crypto@^0.2.0
|
||||||
|
@ -4,20 +4,39 @@
|
|||||||
#include "setup_server.h"
|
#include "setup_server.h"
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include "settings.h"
|
||||||
|
|
||||||
|
#include <ChaChaPoly.h>
|
||||||
|
#include <BLAKE2s.h>
|
||||||
|
|
||||||
|
Environment::Settings settings;
|
||||||
|
utils::byte_buffer passcode(DERIVATION_HASH_SIZE);
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
|
settings.apiID = 11085093266951290551U;
|
||||||
|
settings.endpoint = std::string("http://192.168.64.244:8080/data/authed/");
|
||||||
|
settings.passcode = std::string("password");
|
||||||
|
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
Serial.println("\nSTART");
|
Serial.println("\nSTART");
|
||||||
Serial.print("Last Shutdown: ");
|
Serial.print("Last Shutdown: ");
|
||||||
Serial.println(ESP.getResetReason());
|
Serial.println(ESP.getResetReason());
|
||||||
|
|
||||||
|
Serial.print("Derive Key: ");
|
||||||
|
DeriveKey();
|
||||||
// put your setup code here, to run once:
|
// put your setup code here, to run once:
|
||||||
screen.begin();
|
screen.begin();
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
bme.begin();
|
bme.begin();
|
||||||
environmentUpdate.attach_scheduled(1, UpdateEnvironment);
|
environmentUpdate.attach_scheduled(1, UpdateEnvironment);
|
||||||
environmentPost.attach_scheduled(60, PostEnvironment);
|
environmentPost.attach_scheduled(60, PostEnvironment);
|
||||||
|
screen.firstPage();
|
||||||
|
do
|
||||||
|
{
|
||||||
|
screen.setFont(FONT);
|
||||||
|
screen.drawStr(2, LINE_1, "Connecting...");
|
||||||
|
} while (screen.nextPage());
|
||||||
InitializeWifi();
|
InitializeWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +44,8 @@ void loop()
|
|||||||
{
|
{
|
||||||
// put your main code here, to run repeatedly:
|
// put your main code here, to run repeatedly:
|
||||||
screen.firstPage();
|
screen.firstPage();
|
||||||
do{
|
do
|
||||||
|
{
|
||||||
screen.setFont(FONT);
|
screen.setFont(FONT);
|
||||||
screen.drawStr(2, LINE_1, "Hello World!");
|
screen.drawStr(2, LINE_1, "Hello World!");
|
||||||
screen.drawStr(2, LINE_2, "Hi Butlersaurus!");
|
screen.drawStr(2, LINE_2, "Hi Butlersaurus!");
|
||||||
@ -34,7 +54,8 @@ void loop()
|
|||||||
delay(1000);
|
delay(1000);
|
||||||
|
|
||||||
screen.firstPage();
|
screen.firstPage();
|
||||||
do{
|
do
|
||||||
|
{
|
||||||
screen.setFont(FONT);
|
screen.setFont(FONT);
|
||||||
screen.drawStr(2, LINE_1, TEMP);
|
screen.drawStr(2, LINE_1, TEMP);
|
||||||
screen.setCursor(screen.getStrWidth(TEMP), LINE_1);
|
screen.setCursor(screen.getStrWidth(TEMP), LINE_1);
|
||||||
@ -54,23 +75,56 @@ void UpdateEnvironment()
|
|||||||
void PostEnvironment()
|
void PostEnvironment()
|
||||||
{
|
{
|
||||||
utils::debug_print("Post");
|
utils::debug_print("Post");
|
||||||
requests.begin(client, "http://192.168.64.239/api/environment");
|
//requests.begin(client, "http://192.168.64.239/api/environment");
|
||||||
|
auto endpoint = std::string(settings.endpoint);
|
||||||
|
endpoint.append(std::to_string(settings.apiID));
|
||||||
|
requests.begin(client, endpoint.c_str());
|
||||||
requests.addHeader("Content-Type", "application/json");
|
requests.addHeader("Content-Type", "application/json");
|
||||||
char dataBuffer[128];
|
char dataBuffer[128] = {0};
|
||||||
char formatString[] = "{\"h\":\"%f\",\"t\":\"%f\"}";
|
char formatString[] = "{\"h\":%f,\"t\":%f}";
|
||||||
snprintf(&dataBuffer[0], 128, &formatString[0], humidity, temp);
|
snprintf(&dataBuffer[0], 128, &formatString[0], humidity, temp);
|
||||||
auto code = requests.POST(dataBuffer);
|
auto data = Encrypt(std::string(dataBuffer));
|
||||||
if (code > 0){
|
auto code = requests.PUT(data.get_ptr(), data.get_length());
|
||||||
|
if (code > 0)
|
||||||
|
{
|
||||||
utils::debug_print(code);
|
utils::debug_print(code);
|
||||||
}else{
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
utils::debug_print(requests.errorToString(code));
|
utils::debug_print(requests.errorToString(code));
|
||||||
}
|
}
|
||||||
requests.end();
|
requests.end();
|
||||||
utils::debug_print("Posted");
|
utils::debug_print("Posted");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils::byte_buffer Encrypt(std::string data)
|
||||||
|
{
|
||||||
|
// struct used by go, with basically no docs :|
|
||||||
|
// iv (12) | cipher (x) | tag(16)
|
||||||
|
const uint_fast16_t ivSize = 12;
|
||||||
|
auto size = ivSize + data.length() + 16;
|
||||||
|
auto dataOut = utils::byte_buffer(size);
|
||||||
|
// for the iv
|
||||||
|
dataOut.fill_random();
|
||||||
|
// first 12 bytes
|
||||||
|
auto cipher = ChaChaPoly();
|
||||||
|
|
||||||
|
cipher.setKey(passcode.get_ptr(), passcode.get_length());
|
||||||
|
cipher.setIV(dataOut.get_ptr(), ivSize);
|
||||||
|
|
||||||
|
uint_fast16_t buffLen = 0;
|
||||||
|
auto encryptBuffer = dataOut.get_ptr(ivSize, buffLen);
|
||||||
|
cipher.encrypt(encryptBuffer, (const uint8_t *)data.c_str(), data.length());
|
||||||
|
|
||||||
|
auto tagBuffer = dataOut.get_ptr(ivSize + data.length(), buffLen);
|
||||||
|
cipher.computeTag(tagBuffer, buffLen);
|
||||||
|
|
||||||
|
return dataOut;
|
||||||
|
}
|
||||||
|
|
||||||
void InitializeWifi()
|
void InitializeWifi()
|
||||||
{
|
{
|
||||||
|
delay(1);
|
||||||
WiFi.mode(WIFI_STA);
|
WiFi.mode(WIFI_STA);
|
||||||
WiFi.begin();
|
WiFi.begin();
|
||||||
auto ret = WiFi.waitForConnectResult();
|
auto ret = WiFi.waitForConnectResult();
|
||||||
@ -83,6 +137,16 @@ void InitializeWifi()
|
|||||||
std::string password = std::string();
|
std::string password = std::string();
|
||||||
setup.get_connection(ssid, password);
|
setup.get_connection(ssid, password);
|
||||||
}
|
}
|
||||||
WiFi.setAutoConnect(true);
|
|
||||||
utils::debug_print("Wifi Connected: " + WiFi.SSID());
|
utils::debug_print("Wifi Connected: " + WiFi.SSID());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeriveKey()
|
||||||
|
{
|
||||||
|
BLAKE2s hash = BLAKE2s();
|
||||||
|
hash.reset();
|
||||||
|
hash.update(DERIVATION_SALT, strlen(DERIVATION_SALT));
|
||||||
|
hash.update(settings.passcode.c_str(), settings.passcode.length());
|
||||||
|
hash.finalize(passcode.get_ptr(), passcode.get_length());
|
||||||
|
utils::debug_print(passcode.get_base64());
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
#include <setup_server.h>
|
#include <setup_server.h>
|
||||||
#include <string>
|
|
||||||
#include <html/first_connection_page.h>
|
#include <html/first_connection_page.h>
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
@ -53,7 +53,7 @@ setup_server::SetupErrorCodes setup_server::get_connection(const std::string &ss
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t setup_server::connect_to_ap(const std::string ssid, const std::string password)
|
uint8_t setup_server::connect_to_ap(const std::string &ssid, const std::string &password)
|
||||||
{
|
{
|
||||||
_DEBUG_PRINT("Connecting " + ssid + ":" + password);
|
_DEBUG_PRINT("Connecting " + ssid + ":" + password);
|
||||||
WiFi.begin(ssid.c_str(), password.c_str());
|
WiFi.begin(ssid.c_str(), password.c_str());
|
||||||
@ -65,10 +65,11 @@ void setup_server::root_callback()
|
|||||||
{
|
{
|
||||||
_DEBUG_PRINT("Request \"/\" from " + server->client().remoteIP().toString());
|
_DEBUG_PRINT("Request \"/\" from " + server->client().remoteIP().toString());
|
||||||
auto pageSize = strlen_P(first_connection_page);
|
auto pageSize = strlen_P(first_connection_page);
|
||||||
auto outBuffer = new char(pageSize);
|
auto outBuffer = new char[pageSize + 1];
|
||||||
strncpy_P(outBuffer, first_connection_page, pageSize);
|
strncpy_P(outBuffer, first_connection_page, pageSize);
|
||||||
|
outBuffer[pageSize] = '\0';
|
||||||
server->send(200, "text/html", outBuffer);
|
server->send(200, "text/html", outBuffer);
|
||||||
delete outBuffer;
|
delete[] outBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setup_server::ap_submission_callback()
|
void setup_server::ap_submission_callback()
|
||||||
|
@ -5,6 +5,7 @@ using Microsoft.AspNetCore.Mvc;
|
|||||||
using Microsoft.AspNetCore.Mvc.RazorPages;
|
using Microsoft.AspNetCore.Mvc.RazorPages;
|
||||||
using MongoDB.Bson;
|
using MongoDB.Bson;
|
||||||
using MongoDB.Driver;
|
using MongoDB.Driver;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace ManagementPage.Pages
|
namespace ManagementPage.Pages
|
||||||
{
|
{
|
||||||
@ -44,16 +45,34 @@ namespace ManagementPage.Pages
|
|||||||
return NotFound();
|
return NotFound();
|
||||||
}
|
}
|
||||||
|
|
||||||
var filter = new BsonDocument("ApiID", deviceId);
|
// get the logged in user
|
||||||
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
var filter = new BsonDocument("OpenId", userId);
|
||||||
|
var claims = await _dbClient.AccountsCollection.Find(filter).SingleOrDefaultAsync();
|
||||||
|
|
||||||
|
// No user?
|
||||||
|
if (claims == null)
|
||||||
|
{
|
||||||
|
return Forbid();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the device
|
||||||
|
filter = new BsonDocument("ApiID", deviceId);
|
||||||
device = await _dbClient.DeviceCollection.Find(filter).FirstOrDefaultAsync();
|
device = await _dbClient.DeviceCollection.Find(filter).FirstOrDefaultAsync();
|
||||||
|
|
||||||
FindOptions<EnvironmentData> options = new FindOptions<EnvironmentData>
|
// No device?
|
||||||
|
if (device == null)
|
||||||
{
|
{
|
||||||
Limit = 100,
|
return NotFound();
|
||||||
NoCursorTimeout = false
|
}
|
||||||
};
|
|
||||||
|
|
||||||
using var cursor = await _dbClient.Collection.FindAsync(filter, options);
|
// Device owned by someone else?
|
||||||
|
if (!claims.Devices.Contains(device._id))
|
||||||
|
{
|
||||||
|
return Forbid();
|
||||||
|
}
|
||||||
|
|
||||||
|
using var cursor = await _dbClient.Collection.Find(filter).SortByDescending(x => x.Time).Limit(100).ToCursorAsync();
|
||||||
data.AddRange(await cursor.ToListAsync());
|
data.AddRange(await cursor.ToListAsync());
|
||||||
foreach (var item in data)
|
foreach (var item in data)
|
||||||
{
|
{
|
||||||
@ -61,6 +80,9 @@ namespace ManagementPage.Pages
|
|||||||
temperature.Add(new DataSet() { x = item.Time, y = item.Temperature });
|
temperature.Add(new DataSet() { x = item.Time, y = item.Temperature });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
humidity.Reverse();
|
||||||
|
temperature.Reverse();
|
||||||
|
|
||||||
return Page();
|
return Page();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ namespace ManagementPage.Pages
|
|||||||
foreach (var item in data)
|
foreach (var item in data)
|
||||||
{
|
{
|
||||||
var filter = new BsonDocument("ApiID", item.ApiID);
|
var filter = new BsonDocument("ApiID", item.ApiID);
|
||||||
var envData = await _dbClient.Collection.Find(filter).FirstOrDefaultAsync();
|
var envData = await _dbClient.Collection.Find(filter).SortByDescending(x => x.Time).FirstOrDefaultAsync();
|
||||||
envData ??= new EnvironmentData(item.ApiID, 0, 0, DateTime.UtcNow);
|
envData ??= new EnvironmentData(item.ApiID, 0, 0, DateTime.UtcNow);
|
||||||
currentEnvironment.Add(item.ApiID, envData);
|
currentEnvironment.Add(item.ApiID, envData);
|
||||||
}
|
}
|
||||||
@ -65,9 +65,15 @@ namespace ManagementPage.Pages
|
|||||||
}
|
}
|
||||||
var id = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(),4);
|
var id = BitConverter.ToInt64(Guid.NewGuid().ToByteArray(),4);
|
||||||
var device = new DeviceData(NewDevice.Name, NewDevice.Passcode, id);
|
var device = new DeviceData(NewDevice.Name, NewDevice.Passcode, id);
|
||||||
|
device._id = ObjectId.GenerateNewId();
|
||||||
await _dbClient.DeviceCollection.InsertOneAsync(device);
|
await _dbClient.DeviceCollection.InsertOneAsync(device);
|
||||||
|
|
||||||
return Page();
|
var userId = User.FindFirstValue(ClaimTypes.NameIdentifier);
|
||||||
|
var filter = new BsonDocument("OpenId", userId);
|
||||||
|
var update = Builders<UserData>.Update.AddToSet("Devices", device._id);
|
||||||
|
|
||||||
|
await _dbClient.AccountsCollection.UpdateOneAsync(filter, update);
|
||||||
|
return new RedirectToPageResult("/UserHome");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"commandName": "Project",
|
"commandName": "Project",
|
||||||
"dotnetRunMessages": true,
|
"dotnetRunMessages": true,
|
||||||
"launchBrowser": true,
|
"launchBrowser": true,
|
||||||
"applicationUrl": "https://localhost:8800;http://+:80",
|
"applicationUrl": "https://environment.51m0n.com;http://+:80",
|
||||||
"environmentVariables": {
|
"environmentVariables": {
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
"ASPNETCORE_ENVIRONMENT": "Development"
|
||||||
}
|
}
|
||||||
|
@ -8,5 +8,7 @@
|
|||||||
},
|
},
|
||||||
"oidc": {
|
"oidc": {
|
||||||
"region": "openid-connect",
|
"region": "openid-connect",
|
||||||
|
"clientid": "51m0n-temperature",
|
||||||
|
"clientsecret": "577b32ae-d36e-42ec-b6a2-92025dc16619"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user