Configuration interface
This commit is contained in:
2
README
2
README
@@ -128,6 +128,8 @@ Bauteilliste
|
|||||||
------------
|
------------
|
||||||
|
|
||||||
1x ESP32-S3 Nano (Waveshare)
|
1x ESP32-S3 Nano (Waveshare)
|
||||||
|
berrybase.de
|
||||||
|
eckstein-shop.de
|
||||||
5x Taster schwarz
|
5x Taster schwarz
|
||||||
2x Taster gelb
|
2x Taster gelb
|
||||||
1x M12 Einbaubuchse
|
1x M12 Einbaubuchse
|
||||||
|
|||||||
@@ -9,16 +9,17 @@ lib_deps =
|
|||||||
Preferences
|
Preferences
|
||||||
Wifi
|
Wifi
|
||||||
Wire
|
Wire
|
||||||
|
ArduinoJson @ 6.18.5
|
||||||
ESP32Async/AsyncTCP@3.4.9
|
ESP32Async/AsyncTCP@3.4.9
|
||||||
ESP32Async/ESPAsyncWebServer@3.9.1
|
ESP32Async/ESPAsyncWebServer@3.9.1
|
||||||
ttlappalainen/NMEA2000-library@4.24
|
ttlappalainen/NMEA2000-library@4.24
|
||||||
robtillaart/SHT31@^0.5.2
|
robtillaart/SHT31@^0.5.2
|
||||||
# adafruit/Adafruit NeoPixel
|
|
||||||
|
|
||||||
# only these files will be emedded into firmware
|
# only these files will be emedded into firmware
|
||||||
board_build.embed_files =
|
board_build.embed_files =
|
||||||
lib/generated/index.html.gz
|
lib/generated/index.html.gz
|
||||||
lib/generated/index.js.gz
|
lib/generated/index.js.gz
|
||||||
|
lib/generated/sha256.js.gz
|
||||||
lib/generated/index.css.gz
|
lib/generated/index.css.gz
|
||||||
lib/generated/config.json.gz
|
lib/generated/config.json.gz
|
||||||
|
|
||||||
|
|||||||
169
src/main.cpp
169
src/main.cpp
@@ -1,5 +1,6 @@
|
|||||||
#include <Arduino.h>
|
#include <Arduino.h>
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
#include <WiFi.h>
|
#include <WiFi.h>
|
||||||
#include <AsyncTCP.h>
|
#include <AsyncTCP.h>
|
||||||
#include <ESPAsyncWebServer.h>
|
#include <ESPAsyncWebServer.h>
|
||||||
@@ -12,6 +13,40 @@
|
|||||||
#include "Nmea2kTwai.h"
|
#include "Nmea2kTwai.h"
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
|
|
||||||
|
#include "mbedtls/md.h" // for SHA256
|
||||||
|
#include <esp32/clk.h> // for cpu frequency
|
||||||
|
|
||||||
|
String get_sha256(String payload) {
|
||||||
|
byte shaResult[32];
|
||||||
|
mbedtls_md_context_t ctx;
|
||||||
|
mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256;
|
||||||
|
mbedtls_md_init(&ctx);
|
||||||
|
mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 0);
|
||||||
|
mbedtls_md_starts(&ctx);
|
||||||
|
mbedtls_md_update(&ctx, (const unsigned char *) payload.c_str(), payload.length());
|
||||||
|
mbedtls_md_finish(&ctx, shaResult);
|
||||||
|
mbedtls_md_free(&ctx);
|
||||||
|
// convert to hex string
|
||||||
|
char buffer[sizeof(shaResult)*2 + 1];
|
||||||
|
const char hexmap[] = "0123456789abcdef";
|
||||||
|
for (int i = 0; i < sizeof(shaResult); i++) {
|
||||||
|
buffer[i*2] = hexmap[(shaResult[i] >> 4) & 0x0F];
|
||||||
|
buffer[i*2+1] = hexmap[shaResult[i] & 0x0F];
|
||||||
|
}
|
||||||
|
buffer[sizeof(buffer) - 1] = '\0';
|
||||||
|
String hash = String(buffer);
|
||||||
|
|
||||||
|
Serial.print("SHA256 payload: ");
|
||||||
|
Serial.print(payload);
|
||||||
|
Serial.println();
|
||||||
|
Serial.print("SHA256-Hash: ");
|
||||||
|
Serial.print(hash);
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
// Logging
|
// Logging
|
||||||
static const char* TAG = "main.cpp";
|
static const char* TAG = "main.cpp";
|
||||||
|
|
||||||
@@ -51,10 +86,13 @@ void send_embedded_file(String name, AsyncWebServerRequest *request)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t chipid = ESP.getEfuseMac();
|
||||||
|
|
||||||
const char* wifi_ssid = "OBPKP61";
|
const char* wifi_ssid = "OBPKP61";
|
||||||
const char* wifi_pass = "keypad61";
|
const char* wifi_pass = "keypad61";
|
||||||
AsyncWebServer server(80);
|
AsyncWebServer server(80);
|
||||||
|
|
||||||
|
unsigned long lastSensor = 0;
|
||||||
unsigned long lastPrint = 0;
|
unsigned long lastPrint = 0;
|
||||||
unsigned long counter = 0;
|
unsigned long counter = 0;
|
||||||
|
|
||||||
@@ -70,6 +108,8 @@ uint buzzerpower = 50; // TBD make use of this
|
|||||||
|
|
||||||
SHT31 sht(SHT31_ADDRESS);
|
SHT31 sht(SHT31_ADDRESS);
|
||||||
bool sht_available = false;
|
bool sht_available = false;
|
||||||
|
float temp = 0.0;
|
||||||
|
float hum = 0.0;
|
||||||
|
|
||||||
int nodeid; // NMEA2000 id on bus
|
int nodeid; // NMEA2000 id on bus
|
||||||
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
|
Nmea2kTwai &NMEA2000=*(new Nmea2kTwai(CAN_TX, CAN_RX, CAN_RECOVERY_PERIOD));
|
||||||
@@ -80,44 +120,25 @@ String processor(const String& var) {
|
|||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Low level wifi setup (alternative)
|
String uptime_with_unit() {
|
||||||
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
|
int64_t uptime = esp_timer_get_time() / 1000000;
|
||||||
int32_t event_id, void* event_data)
|
String uptime_unit;
|
||||||
{
|
if (uptime < 120) {
|
||||||
// printf("Event nr: %ld!\n", event_id);
|
uptime_unit = " seconds";
|
||||||
|
} else {
|
||||||
|
if (uptime < 2 * 3600) {
|
||||||
|
uptime /= 60;
|
||||||
|
uptime_unit = " minutes";
|
||||||
|
} else if (uptime < 2 * 3600 * 24) {
|
||||||
|
uptime /= 3600;
|
||||||
|
uptime_unit = " hours";
|
||||||
|
} else {
|
||||||
|
uptime /= 86400;
|
||||||
|
uptime_unit = " days";
|
||||||
}
|
}
|
||||||
|
|
||||||
void wifi_init_softap()
|
|
||||||
{
|
|
||||||
esp_netif_init();
|
|
||||||
esp_event_loop_create_default();
|
|
||||||
esp_netif_create_default_wifi_ap();
|
|
||||||
|
|
||||||
wifi_init_config_t cfg = WIFI_INIT_CONFIG_DEFAULT();
|
|
||||||
esp_event_handler_instance_register(WIFI_EVENT, ESP_EVENT_ANY_ID, &wifi_event_handler, NULL, NULL);
|
|
||||||
esp_wifi_init(&cfg);
|
|
||||||
wifi_config_t wifi_config = {
|
|
||||||
.ap = {
|
|
||||||
.ssid = wifi_ssid,
|
|
||||||
.ssid_len = strlen(wifi_ssid),
|
|
||||||
.channel = WIFI_CHANNEL,
|
|
||||||
.password = wifi_pass,
|
|
||||||
.max_connection = WIFI_MAX_STA,
|
|
||||||
.authmode = WIFI_AUTH_WPA2_PSK,
|
|
||||||
.pmf_cfg = {
|
|
||||||
.required = true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
esp_wifi_set_mode(WIFI_MODE_AP);
|
|
||||||
esp_wifi_set_config(WIFI_IF_AP, &wifi_config);
|
|
||||||
esp_wifi_start();
|
|
||||||
|
|
||||||
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
|
|
||||||
ESP_WIFI_SSID, ESP_WIFI_PASS, ESP_WIFI_CHANNEL);
|
|
||||||
}
|
}
|
||||||
*/
|
return String(uptime) + " " + uptime_unit;
|
||||||
|
}
|
||||||
|
|
||||||
void setup() {
|
void setup() {
|
||||||
|
|
||||||
@@ -167,16 +188,65 @@ void setup() {
|
|||||||
send_embedded_file(it->first, request);
|
send_embedded_file(it->first, request);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// WIP: API
|
// API fast hack
|
||||||
/*
|
server.on("/api/capabilities", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
|
||||||
StaticJsonDocument<100> doc;
|
StaticJsonDocument<100> doc;
|
||||||
doc["temp"] = 22.3;
|
doc["apPwChange"] = "true";
|
||||||
doc["ip"] = WiFi.localIP().toString();
|
|
||||||
String out;
|
String out;
|
||||||
serializeJson(doc, out);
|
serializeJson(doc, out);
|
||||||
request->send(200, "application/json", out);
|
request->send(200, "application/json", out);
|
||||||
}); */
|
});
|
||||||
|
server.on("/api/checkpass", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
server.on("/api/config", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["systemName"] = "Keypad1";
|
||||||
|
doc["version"] = "0.0";
|
||||||
|
doc["fwtype"] = "unknown";
|
||||||
|
doc["salt"] = "secret";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
server.on("/api/resetconfig", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
server.on("/api/status", HTTP_GET, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
|
||||||
|
int cpu_freq = esp_clk_cpu_freq() / 1000000;
|
||||||
|
doc["cpuspeed"] = String(cpu_freq) + "MHz";
|
||||||
|
|
||||||
|
char ssid[13];
|
||||||
|
snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid);
|
||||||
|
doc["chipid"] = String(ssid);
|
||||||
|
|
||||||
|
doc["uptime"] = uptime_with_unit();
|
||||||
|
doc["heap"]=(long)xPortGetFreeHeapSize();
|
||||||
|
doc["temp"] = String(temp, 1);
|
||||||
|
doc["hum"] = String(hum, 1);
|
||||||
|
doc["status"] = "OK";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
server.on("/api/setconfig", HTTP_POST, [](AsyncWebServerRequest *request){
|
||||||
|
StaticJsonDocument<100> doc;
|
||||||
|
doc["status"] = "FAILED";
|
||||||
|
String out;
|
||||||
|
serializeJson(doc, out);
|
||||||
|
request->send(200, "application/json", out);
|
||||||
|
});
|
||||||
|
|
||||||
// TODO POST vom Client entgegennehmen
|
// TODO POST vom Client entgegennehmen
|
||||||
|
|
||||||
server.begin();
|
server.begin();
|
||||||
@@ -299,6 +369,9 @@ void setup() {
|
|||||||
Serial.print(stat, HEX);
|
Serial.print(stat, HEX);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
|
|
||||||
|
// Additional tests
|
||||||
|
String passhash = get_sha256("secretTEST");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
@@ -390,10 +463,9 @@ void loop() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (button > 0) {
|
if (button > 0) {
|
||||||
sht.read();
|
Serial.print(temp, 1);
|
||||||
Serial.print(sht.getTemperature(), 1);
|
|
||||||
Serial.print("\t");
|
Serial.print("\t");
|
||||||
Serial.println(sht.getHumidity(), 1);
|
Serial.println(hum, 1);
|
||||||
// Debounce delay to avoid multiple triggers
|
// Debounce delay to avoid multiple triggers
|
||||||
delay(200);
|
delay(200);
|
||||||
}
|
}
|
||||||
@@ -402,6 +474,13 @@ void loop() {
|
|||||||
// NMEA2000.loop();
|
// NMEA2000.loop();
|
||||||
// NMEA2000.ParseMessages();
|
// NMEA2000.ParseMessages();
|
||||||
|
|
||||||
|
if (millis() - lastSensor >= 5000) {
|
||||||
|
lastSensor = millis();
|
||||||
|
sht.read();
|
||||||
|
temp = sht.getTemperature();
|
||||||
|
hum = sht.getHumidity();
|
||||||
|
}
|
||||||
|
|
||||||
// development heartbeat
|
// development heartbeat
|
||||||
if (millis() - lastPrint >= 1000) {
|
if (millis() - lastPrint >= 1000) {
|
||||||
lastPrint = millis();
|
lastPrint = millis();
|
||||||
|
|||||||
119
web/config.json
119
web/config.json
@@ -1,20 +1,129 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"name": "systemName",
|
"name": "systemName",
|
||||||
"label": "system name",
|
"label": "System name",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "OBPkeypad61",
|
"default": "OBPkeypad61",
|
||||||
"check": "checkSystemName",
|
"check": "checkSystemName",
|
||||||
"description": "system name, used for the access point and for services",
|
"description": "System name, used also for the access point SSID.",
|
||||||
"category": "system"
|
"category": "System"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "logLevel",
|
||||||
|
"label": "Log level",
|
||||||
|
"type": "list",
|
||||||
|
"default": "0",
|
||||||
|
"list": [
|
||||||
|
{"l":"Off (0)","v":0},
|
||||||
|
{"l":"Error (1)","v":1},
|
||||||
|
{"l":"Warning (2)","v":2},
|
||||||
|
{"l":"Info (3)","v":3},
|
||||||
|
{"l":"Debug (4)","v":4},
|
||||||
|
{"l":"Verbose (5)","v":5}
|
||||||
|
],
|
||||||
|
"description": "Log level at the USB port.\nHigher level means more output.",
|
||||||
|
"category": "System"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "adminPassword",
|
||||||
|
"label": "Admin Password",
|
||||||
|
"type": "password",
|
||||||
|
"default": "esp32admin",
|
||||||
|
"check": "checkAdminPass",
|
||||||
|
"description": "Set the password for config modifications",
|
||||||
|
"category": "System"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "useAdminPass",
|
||||||
|
"label": "Use Admin-Pass",
|
||||||
|
"type": "boolean",
|
||||||
|
"default": "true",
|
||||||
|
"description": "A password for config modifications is required.",
|
||||||
|
"category": "System"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "apPassword",
|
"name": "apPassword",
|
||||||
|
"label": "Wifi password",
|
||||||
"type": "password",
|
"type": "password",
|
||||||
"default": "keypad61",
|
"default": "keypad61",
|
||||||
"check": "checkApPass",
|
"check": "checkApPass",
|
||||||
"description": "set the password for the Wifi access point",
|
"description": "Set the password for the Wifi access point.",
|
||||||
"category": "system",
|
"category": "Wifi",
|
||||||
"capabilities":{"apPwChange":["true"]}
|
"capabilities":{"apPwChange":["true"]}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apIp",
|
||||||
|
"label": "AP IP-Address",
|
||||||
|
"type": "string",
|
||||||
|
"default":"192.168.15.1",
|
||||||
|
"check": "checkApIp",
|
||||||
|
"description": "The IP address for the wifi access point.\nClients will get addresses within the same subnet.",
|
||||||
|
"category":"Wifi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "apMask",
|
||||||
|
"label": "AP Net-Mask",
|
||||||
|
"type": "string",
|
||||||
|
"default": "255.255.255.0",
|
||||||
|
"check": "checkNetMask",
|
||||||
|
"description": "The network mask for the access point.",
|
||||||
|
"category": "Wifi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "stopApTime",
|
||||||
|
"label": "AP time off",
|
||||||
|
"type": "number",
|
||||||
|
"default": "0",
|
||||||
|
"min": 0,
|
||||||
|
"max": 60,
|
||||||
|
"check": "checkMinMax",
|
||||||
|
"description": "Stop the access point after that many minutes if not used.\n1 to 60 minutes.\n\n'0' means that the access point is permanently enabled.",
|
||||||
|
"category": "Wifi"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "cpuSpeed",
|
||||||
|
"label": "CPU Speed [MHz]",
|
||||||
|
"type": "list",
|
||||||
|
"default": "160",
|
||||||
|
"list": [
|
||||||
|
"80",
|
||||||
|
"160",
|
||||||
|
"240"
|
||||||
|
],
|
||||||
|
"description": "CPU speed in MHz [80|160|240].\nSlower speed means less power consumption.",
|
||||||
|
"category": "Hardware"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ledBrightness",
|
||||||
|
"label": "LED brightness",
|
||||||
|
"type": "number",
|
||||||
|
"default": 64,
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"description": "The brightness of the destination leds (0..255).",
|
||||||
|
"category": "Hardware"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "ledRgbBrightness",
|
||||||
|
"label": "RGB-LED brightness",
|
||||||
|
"type": "number",
|
||||||
|
"default": 64,
|
||||||
|
"min": 0,
|
||||||
|
"max": 255,
|
||||||
|
"description": "The brightness of the rgb status led (0..255).",
|
||||||
|
"category": "Hardware"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "tempFormat",
|
||||||
|
"label": "Temperature Format",
|
||||||
|
"type": "list",
|
||||||
|
"default": "C",
|
||||||
|
"list": [
|
||||||
|
"K",
|
||||||
|
"C",
|
||||||
|
"F"
|
||||||
|
],
|
||||||
|
"description": "Temperature format: Kelvin, Celsius or Fahrenheit [K|C|F].",
|
||||||
|
"category": "Units"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
291
web/index.css
291
web/index.css
@@ -0,0 +1,291 @@
|
|||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: Arial, Helvetica, sans-serif;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
margin: 0.2em;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
#tabs .tab {
|
||||||
|
background-color: lightgray;
|
||||||
|
padding: 0.5em;
|
||||||
|
/*border: 1px;
|
||||||
|
border-color: grey;
|
||||||
|
border-style: solid; */
|
||||||
|
border: 1px solid grey;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
#tabs .tab.active {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tabPages {
|
||||||
|
overflow: auto;
|
||||||
|
padding-bottom: 1ex;
|
||||||
|
border-bottom: 1px solid grey;
|
||||||
|
}
|
||||||
|
|
||||||
|
.configForm {
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.configForm .buttons {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.configForm .content>div:nth-child(even) {
|
||||||
|
background-color: rgb(211 211 211 / 43%);
|
||||||
|
}
|
||||||
|
#statusPage .even {
|
||||||
|
background-color: rgb(211 211 211 / 43%);
|
||||||
|
}
|
||||||
|
#statusPageContent {
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
.counter-row .value{
|
||||||
|
text-align: right;
|
||||||
|
width: 6em;
|
||||||
|
}
|
||||||
|
.icon-row .label{
|
||||||
|
width: 8.7em;
|
||||||
|
}
|
||||||
|
.category .title .label {
|
||||||
|
opacity: 1;
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
.changed input{
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.changed select{
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
.category.changed{
|
||||||
|
color: green;
|
||||||
|
}
|
||||||
|
span.label {
|
||||||
|
width: 10em;
|
||||||
|
display: inline-block;
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
.configForm .value {
|
||||||
|
width: 21em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
margin-bottom: 0.2em;
|
||||||
|
}
|
||||||
|
span#connected {
|
||||||
|
display: inline-block;
|
||||||
|
background-color: red;
|
||||||
|
width: 1em;
|
||||||
|
height: 1em;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
span#connected.ok{
|
||||||
|
background-color: #13ac13;
|
||||||
|
}
|
||||||
|
.row {
|
||||||
|
padding: 0.5em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
input,select {
|
||||||
|
border: 1px solid #808080a1;
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 0.2em;
|
||||||
|
}
|
||||||
|
.filter {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
button.infoButton {
|
||||||
|
margin-left: 1em;
|
||||||
|
vertical-align: bottom;
|
||||||
|
}
|
||||||
|
.category .title {
|
||||||
|
padding-left: 0.5em;
|
||||||
|
background-color: lightgray;
|
||||||
|
padding-top: 0.3em;
|
||||||
|
padding-bottom: 0.5em;
|
||||||
|
border-bottom: 1px solid darkgray;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.value button {
|
||||||
|
margin-left: 0.5em;
|
||||||
|
}
|
||||||
|
.hidden{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
.dash.invalid{
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
button.addunassigned {
|
||||||
|
margin-left: 1em;
|
||||||
|
}
|
||||||
|
.msgDetails .value {
|
||||||
|
width: 5em;
|
||||||
|
text-align: right;
|
||||||
|
}
|
||||||
|
.msgDetails .label {
|
||||||
|
width: 5em;
|
||||||
|
}
|
||||||
|
.overlayContainer {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background-color: #80808070;
|
||||||
|
display: flex;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.overlay {
|
||||||
|
margin: auto;
|
||||||
|
background-color: white;
|
||||||
|
padding: 0.5em;
|
||||||
|
max-width: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
.overlayContent {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
div#overlayContent.text{
|
||||||
|
white-space: pre-line;
|
||||||
|
}
|
||||||
|
.overlayButtons {
|
||||||
|
border-top: 1px solid grey;
|
||||||
|
padding-top: 0.5em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: end;
|
||||||
|
}
|
||||||
|
.buttons button {
|
||||||
|
margin: 0.2ex 0;
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
.overlayButtons button {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin-left: 0.3em;
|
||||||
|
}
|
||||||
|
button#reset {
|
||||||
|
padding: 0.5em;
|
||||||
|
}
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.icon-eye {
|
||||||
|
background-image: url("data:image/svg+xml;utf-8,<svg width='24' height='24' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'> <g class='layer'> <title>Layer 1</title> <path d='m0,0l24,0l0,24l-24,0l0,-24z' fill='none' id='svg_1'/> <path d='m12,6c3.79,0 7.17,2.13 8.82,5.5c-1.65,3.37 -5.03,5.5 -8.82,5.5s-7.17,-2.13 -8.82,-5.5c1.65,-3.37 5.03,-5.5 8.82,-5.5m0,-2c-5,0 -9.27,3.11 -11,7.5c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zm0,5c1.38,0 2.5,1.12 2.5,2.5s-1.12,2.5 -2.5,2.5s-2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5m0,-2c-2.48,0 -4.5,2.02 -4.5,4.5s2.02,4.5 4.5,4.5s4.5,-2.02 4.5,-4.5s-2.02,-4.5 -4.5,-4.5z' id='svg_2'/> </g> </svg>");
|
||||||
|
margin-left: 0.5em;
|
||||||
|
opacity: 0.3;
|
||||||
|
}
|
||||||
|
.icon{
|
||||||
|
height: 1.5em;
|
||||||
|
width: 1.5em;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.icon-more{
|
||||||
|
background-image: url("data:image/svg+xml;utf-8,<svg width='24' height='24' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'> <g class='layer'> <title>Layer 1</title> <path d='m24,24l-24,0l0,-24l24,0l0,24z' fill='none' id='svg_1' opacity='0.87'/> <path d='m16.59,8.59l-4.59,4.58l-4.59,-4.58l-1.41,1.41l6,6l6,-6l-1.41,-1.41z' id='svg_2'/> </g> </svg>");
|
||||||
|
}
|
||||||
|
.icon-less{
|
||||||
|
background-image: url("data:image/svg+xml;utf-8,<svg width='24' height='24' xmlns='http://www.w3.org/2000/svg' xmlns:svg='http://www.w3.org/2000/svg'> <g class='layer'> <title>Layer 1</title> <path d='m0,0l24,0l0,24l-24,0l0,-24z' fill='none' id='svg_1'/> <path d='m12,8l-6,6l1.41,1.41l4.59,-4.58l4.59,4.58l1.41,-1.41l-6,-6z' id='svg_2'/> </g> </svg>");
|
||||||
|
}
|
||||||
|
.icon-eye.active{
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dash {
|
||||||
|
width: 6.5em;
|
||||||
|
height: 4em;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border: 1px solid grey;
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
font-size: 1.2em;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
div#dashboardPage {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
.dashTitle {
|
||||||
|
font-size: 0.8em;
|
||||||
|
background-color: lightgray;
|
||||||
|
}
|
||||||
|
.dashValue{
|
||||||
|
font-size: 1.6em;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.dashValue.formatLatitude {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
.dashValue.formatLongitude {
|
||||||
|
font-size: 1.1em;
|
||||||
|
}
|
||||||
|
.dashValue.formatDate {
|
||||||
|
font-size: 1.2em;
|
||||||
|
}
|
||||||
|
.footer {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
padding: 0.1em;
|
||||||
|
background-color: lightgray;
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
.footer .unit{
|
||||||
|
}
|
||||||
|
.footer .source{
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
#adminPassInput {
|
||||||
|
margin-bottom: 1em;
|
||||||
|
}
|
||||||
|
input#uploadFile {
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
div#uploadProgress {
|
||||||
|
width: 100%;
|
||||||
|
max-width: 20em;
|
||||||
|
height: 1em;
|
||||||
|
margin-left: 1em;
|
||||||
|
/* margin-right: auto; */
|
||||||
|
border: 1px solid grey;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
}
|
||||||
|
#uploadDone{
|
||||||
|
background-color: blue;
|
||||||
|
width: 0px;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
.error{
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
input.error{
|
||||||
|
background-color: rgba(255, 0, 0, 0.329);
|
||||||
|
}
|
||||||
|
|||||||
163
web/index.html
163
web/index.html
@@ -1,17 +1,166 @@
|
|||||||
<!DOCTYPE HTML>
|
<!DOCTYPE html>
|
||||||
<html>
|
<html><head>
|
||||||
<head>
|
|
||||||
<title>OBPkeypad 6/1</title>
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<title>OBPkeyboard 6/1</title>
|
||||||
<link rel="icon" href="data:,">
|
<link rel="icon" href="data:,">
|
||||||
|
<script>
|
||||||
|
if (!window.isSecureContext) {
|
||||||
|
const s = document.createElement('script');
|
||||||
|
s.src = 'sha256.js';
|
||||||
|
document.head.appendChild(s);
|
||||||
|
}
|
||||||
|
</script>
|
||||||
<script type="text/javascript" src="index.js"></script>
|
<script type="text/javascript" src="index.js"></script>
|
||||||
<link rel="stylesheet" href="index.css">
|
<link rel="stylesheet" href="index.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div class="main">
|
<div class="main">
|
||||||
<h1>OBPkeypad 6/1</h1>
|
<h1 id="headline">OBPkb</h1>
|
||||||
<p>Work in progress</p>
|
<div class="row">
|
||||||
<p><a href="https://computerclub.hoogi.de/obpkeypad/">Furter Information</a></p>
|
<span class="label" id="conn_label">disconnected</span>
|
||||||
|
<span class="value" id="connected"></span>
|
||||||
</div>
|
</div>
|
||||||
|
<div id="tabs">
|
||||||
|
<div class="tab active" data-page="statusPage">Status</div>
|
||||||
|
<div class="tab" data-page="configPage">Config</div>
|
||||||
|
<div class="tab" data-page="updatePage">Update</div>
|
||||||
|
<div class="tab" data-url="https://computerclub.hoogi.de/obpkeypad" data-window="help" id="helpButton">Help</div>
|
||||||
|
</div>
|
||||||
|
<div id="tabPages">
|
||||||
|
|
||||||
|
<div id="statusPage" class="tabPage">
|
||||||
|
<div id="statusPageContent">
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Firmware</span>
|
||||||
|
<span class="value" id="version">---</span>
|
||||||
|
<button class="infoButton" id="converterInfo">?</button>
|
||||||
|
</div>
|
||||||
|
<div class="row even">
|
||||||
|
<span class="label">MCU-ID</span>
|
||||||
|
<span class="value" id="chipid">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">CPU speed</span>
|
||||||
|
<span class="value" id="cpuspeed">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row even">
|
||||||
|
<span class="label">Free heap</span>
|
||||||
|
<span class="value" id="heap">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Uptime</span>
|
||||||
|
<span class="value" id="uptime">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row even">
|
||||||
|
<span class="label">NMEA2000 State</span>
|
||||||
|
[<span class="value" id="n2knode">---</span>]
|
||||||
|
<span class="value" id="n2kstate">UNKNOWN</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Dest A</span>
|
||||||
|
<span class="value" id="destA">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row even">
|
||||||
|
<span class="label">Dest B</span>
|
||||||
|
<span class="value" id="destB">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Dest C</span>
|
||||||
|
<span class="value" id="destC">---</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row even">
|
||||||
|
<span class="label">Sensor: Temperature</span>
|
||||||
|
<span class="value" id="temp">---</span>°C
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Sensor: Humidity</span>
|
||||||
|
<span class="value" id="hum">---</span>%
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<button id="reset">Reset</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="configForm tabPage hidden" id="configPage">
|
||||||
|
<div class="buttons">
|
||||||
|
<button id="resetForm">ReloadConfig</button>
|
||||||
|
<button id="forgetPass">ForgetPass</button>
|
||||||
|
<button id="changeConfig">Save&Restart</button>
|
||||||
|
<button id="exportConfig">Export</button>
|
||||||
|
<button id="importConfig">Import</button>
|
||||||
|
<button id="factoryReset">FactoryReset</button>
|
||||||
|
</div>
|
||||||
|
<div class="configFormRows">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="tabPage hidden" id="updatePage">
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Firmware type</span>
|
||||||
|
<span class="value status-fwtype">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Chip type</span>
|
||||||
|
<span class="value status-chipid">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">Current version</span>
|
||||||
|
<span class="value status-version">---</span>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">New Firmware</span>
|
||||||
|
<input type="file" name="file1" id="uploadFile">
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<span class="label"></span>
|
||||||
|
<span id="imageProperties" class="value"></span>
|
||||||
|
</div>
|
||||||
|
<div id="uploadProgress">
|
||||||
|
<div id="uploadDone"></div>
|
||||||
|
</div>
|
||||||
|
<div class="buttons">
|
||||||
|
<button id="uploadBin">Upload</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overlayContainer hidden" id="overlayContainer">
|
||||||
|
<div id="overlay" class="overlay">
|
||||||
|
<div id="overlayContent" class="overlayContent">
|
||||||
|
AHA
|
||||||
|
</div>
|
||||||
|
<div class="overlayButtons">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="overlayContainer hidden" id="adminPassOverlay">
|
||||||
|
<div id="adminPassOverlay" class="overlay">
|
||||||
|
<div id="adminPassOverlayContent" class="overlayContent">
|
||||||
|
<h2>Admin Password</h2>
|
||||||
|
<div id="adminPassHint"></div>
|
||||||
|
<div id="adminPassError" ></div>
|
||||||
|
<input id="adminPassInput" type="password">
|
||||||
|
<div class="row">
|
||||||
|
<span class="label">remember me</span>
|
||||||
|
<select id="adminPassKeep">
|
||||||
|
<option value="true">on</option>
|
||||||
|
<option value="false" selected>off</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="overlayButtons">
|
||||||
|
<button id="adminPassCancel">Cancel</button>
|
||||||
|
<button id="adminPassOk">OK</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
1643
web/index.js
1643
web/index.js
File diff suppressed because it is too large
Load Diff
526
web/sha256.js
Normal file
526
web/sha256.js
Normal file
@@ -0,0 +1,526 @@
|
|||||||
|
/**
|
||||||
|
* [js-sha256]{@link https://github.com/emn178/js-sha256}
|
||||||
|
*
|
||||||
|
* @version 0.11.1
|
||||||
|
* @author Chen, Yi-Cyuan [emn178@gmail.com]
|
||||||
|
* @copyright Chen, Yi-Cyuan 2014-2025
|
||||||
|
* @license MIT
|
||||||
|
*/
|
||||||
|
/*jslint bitwise: true */
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ERROR = 'input is invalid type';
|
||||||
|
var WINDOW = typeof window === 'object';
|
||||||
|
var root = WINDOW ? window : {};
|
||||||
|
if (root.JS_SHA256_NO_WINDOW) {
|
||||||
|
WINDOW = false;
|
||||||
|
}
|
||||||
|
var WEB_WORKER = !WINDOW && typeof self === 'object';
|
||||||
|
var NODE_JS = !root.JS_SHA256_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node && process.type != 'renderer';
|
||||||
|
if (NODE_JS) {
|
||||||
|
root = global;
|
||||||
|
} else if (WEB_WORKER) {
|
||||||
|
root = self;
|
||||||
|
}
|
||||||
|
var COMMON_JS = !root.JS_SHA256_NO_COMMON_JS && typeof module === 'object' && module.exports;
|
||||||
|
var AMD = typeof define === 'function' && define.amd;
|
||||||
|
var ARRAY_BUFFER = !root.JS_SHA256_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
|
||||||
|
var HEX_CHARS = '0123456789abcdef'.split('');
|
||||||
|
var EXTRA = [-2147483648, 8388608, 32768, 128];
|
||||||
|
var SHIFT = [24, 16, 8, 0];
|
||||||
|
var K = [
|
||||||
|
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||||
|
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||||
|
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||||
|
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||||
|
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||||
|
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||||
|
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||||
|
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||||
|
];
|
||||||
|
var OUTPUT_TYPES = ['hex', 'array', 'digest', 'arrayBuffer'];
|
||||||
|
|
||||||
|
var blocks = [];
|
||||||
|
|
||||||
|
if (root.JS_SHA256_NO_NODE_JS || !Array.isArray) {
|
||||||
|
Array.isArray = function (obj) {
|
||||||
|
return Object.prototype.toString.call(obj) === '[object Array]';
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ARRAY_BUFFER && (root.JS_SHA256_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) {
|
||||||
|
ArrayBuffer.isView = function (obj) {
|
||||||
|
return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
var createOutputMethod = function (outputType, is224) {
|
||||||
|
return function (message) {
|
||||||
|
return new Sha256(is224, true).update(message)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createMethod = function (is224) {
|
||||||
|
var method = createOutputMethod('hex', is224);
|
||||||
|
if (NODE_JS) {
|
||||||
|
method = nodeWrap(method, is224);
|
||||||
|
}
|
||||||
|
method.create = function () {
|
||||||
|
return new Sha256(is224);
|
||||||
|
};
|
||||||
|
method.update = function (message) {
|
||||||
|
return method.create().update(message);
|
||||||
|
};
|
||||||
|
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
|
||||||
|
var type = OUTPUT_TYPES[i];
|
||||||
|
method[type] = createOutputMethod(type, is224);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
};
|
||||||
|
|
||||||
|
var nodeWrap = function (method, is224) {
|
||||||
|
var crypto = require('crypto')
|
||||||
|
var Buffer = require('buffer').Buffer;
|
||||||
|
var algorithm = is224 ? 'sha224' : 'sha256';
|
||||||
|
var bufferFrom;
|
||||||
|
if (Buffer.from && !root.JS_SHA256_NO_BUFFER_FROM) {
|
||||||
|
bufferFrom = Buffer.from;
|
||||||
|
} else {
|
||||||
|
bufferFrom = function (message) {
|
||||||
|
return new Buffer(message);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var nodeMethod = function (message) {
|
||||||
|
if (typeof message === 'string') {
|
||||||
|
return crypto.createHash(algorithm).update(message, 'utf8').digest('hex');
|
||||||
|
} else {
|
||||||
|
if (message === null || message === undefined) {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
} else if (message.constructor === ArrayBuffer) {
|
||||||
|
message = new Uint8Array(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Array.isArray(message) || ArrayBuffer.isView(message) ||
|
||||||
|
message.constructor === Buffer) {
|
||||||
|
return crypto.createHash(algorithm).update(bufferFrom(message)).digest('hex');
|
||||||
|
} else {
|
||||||
|
return method(message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return nodeMethod;
|
||||||
|
};
|
||||||
|
|
||||||
|
var createHmacOutputMethod = function (outputType, is224) {
|
||||||
|
return function (key, message) {
|
||||||
|
return new HmacSha256(key, is224, true).update(message)[outputType]();
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
var createHmacMethod = function (is224) {
|
||||||
|
var method = createHmacOutputMethod('hex', is224);
|
||||||
|
method.create = function (key) {
|
||||||
|
return new HmacSha256(key, is224);
|
||||||
|
};
|
||||||
|
method.update = function (key, message) {
|
||||||
|
return method.create(key).update(message);
|
||||||
|
};
|
||||||
|
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
|
||||||
|
var type = OUTPUT_TYPES[i];
|
||||||
|
method[type] = createHmacOutputMethod(type, is224);
|
||||||
|
}
|
||||||
|
return method;
|
||||||
|
};
|
||||||
|
|
||||||
|
function Sha256(is224, sharedMemory) {
|
||||||
|
if (sharedMemory) {
|
||||||
|
blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
|
||||||
|
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
|
||||||
|
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
|
||||||
|
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
|
||||||
|
this.blocks = blocks;
|
||||||
|
} else {
|
||||||
|
this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is224) {
|
||||||
|
this.h0 = 0xc1059ed8;
|
||||||
|
this.h1 = 0x367cd507;
|
||||||
|
this.h2 = 0x3070dd17;
|
||||||
|
this.h3 = 0xf70e5939;
|
||||||
|
this.h4 = 0xffc00b31;
|
||||||
|
this.h5 = 0x68581511;
|
||||||
|
this.h6 = 0x64f98fa7;
|
||||||
|
this.h7 = 0xbefa4fa4;
|
||||||
|
} else { // 256
|
||||||
|
this.h0 = 0x6a09e667;
|
||||||
|
this.h1 = 0xbb67ae85;
|
||||||
|
this.h2 = 0x3c6ef372;
|
||||||
|
this.h3 = 0xa54ff53a;
|
||||||
|
this.h4 = 0x510e527f;
|
||||||
|
this.h5 = 0x9b05688c;
|
||||||
|
this.h6 = 0x1f83d9ab;
|
||||||
|
this.h7 = 0x5be0cd19;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.block = this.start = this.bytes = this.hBytes = 0;
|
||||||
|
this.finalized = this.hashed = false;
|
||||||
|
this.first = true;
|
||||||
|
this.is224 = is224;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sha256.prototype.update = function (message) {
|
||||||
|
if (this.finalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var notString, type = typeof message;
|
||||||
|
if (type !== 'string') {
|
||||||
|
if (type === 'object') {
|
||||||
|
if (message === null) {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
} else if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
|
||||||
|
message = new Uint8Array(message);
|
||||||
|
} else if (!Array.isArray(message)) {
|
||||||
|
if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
}
|
||||||
|
notString = true;
|
||||||
|
}
|
||||||
|
var code, index = 0, i, length = message.length, blocks = this.blocks;
|
||||||
|
while (index < length) {
|
||||||
|
if (this.hashed) {
|
||||||
|
this.hashed = false;
|
||||||
|
blocks[0] = this.block;
|
||||||
|
this.block = blocks[16] = blocks[1] = blocks[2] = blocks[3] =
|
||||||
|
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
|
||||||
|
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
|
||||||
|
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (notString) {
|
||||||
|
for (i = this.start; index < length && i < 64; ++index) {
|
||||||
|
blocks[i >>> 2] |= message[index] << SHIFT[i++ & 3];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (i = this.start; index < length && i < 64; ++index) {
|
||||||
|
code = message.charCodeAt(index);
|
||||||
|
if (code < 0x80) {
|
||||||
|
blocks[i >>> 2] |= code << SHIFT[i++ & 3];
|
||||||
|
} else if (code < 0x800) {
|
||||||
|
blocks[i >>> 2] |= (0xc0 | (code >>> 6)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
} else if (code < 0xd800 || code >= 0xe000) {
|
||||||
|
blocks[i >>> 2] |= (0xe0 | (code >>> 12)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
} else {
|
||||||
|
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
|
||||||
|
blocks[i >>> 2] |= (0xf0 | (code >>> 18)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | ((code >>> 12) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | ((code >>> 6) & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
blocks[i >>> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.lastByteIndex = i;
|
||||||
|
this.bytes += i - this.start;
|
||||||
|
if (i >= 64) {
|
||||||
|
this.block = blocks[16];
|
||||||
|
this.start = i - 64;
|
||||||
|
this.hash();
|
||||||
|
this.hashed = true;
|
||||||
|
} else {
|
||||||
|
this.start = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.bytes > 4294967295) {
|
||||||
|
this.hBytes += this.bytes / 4294967296 << 0;
|
||||||
|
this.bytes = this.bytes % 4294967296;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sha256.prototype.finalize = function () {
|
||||||
|
if (this.finalized) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.finalized = true;
|
||||||
|
var blocks = this.blocks, i = this.lastByteIndex;
|
||||||
|
blocks[16] = this.block;
|
||||||
|
blocks[i >>> 2] |= EXTRA[i & 3];
|
||||||
|
this.block = blocks[16];
|
||||||
|
if (i >= 56) {
|
||||||
|
if (!this.hashed) {
|
||||||
|
this.hash();
|
||||||
|
}
|
||||||
|
blocks[0] = this.block;
|
||||||
|
blocks[16] = blocks[1] = blocks[2] = blocks[3] =
|
||||||
|
blocks[4] = blocks[5] = blocks[6] = blocks[7] =
|
||||||
|
blocks[8] = blocks[9] = blocks[10] = blocks[11] =
|
||||||
|
blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0;
|
||||||
|
}
|
||||||
|
blocks[14] = this.hBytes << 3 | this.bytes >>> 29;
|
||||||
|
blocks[15] = this.bytes << 3;
|
||||||
|
this.hash();
|
||||||
|
};
|
||||||
|
|
||||||
|
Sha256.prototype.hash = function () {
|
||||||
|
var a = this.h0, b = this.h1, c = this.h2, d = this.h3, e = this.h4, f = this.h5, g = this.h6,
|
||||||
|
h = this.h7, blocks = this.blocks, j, s0, s1, maj, t1, t2, ch, ab, da, cd, bc;
|
||||||
|
|
||||||
|
for (j = 16; j < 64; ++j) {
|
||||||
|
// rightrotate
|
||||||
|
t1 = blocks[j - 15];
|
||||||
|
s0 = ((t1 >>> 7) | (t1 << 25)) ^ ((t1 >>> 18) | (t1 << 14)) ^ (t1 >>> 3);
|
||||||
|
t1 = blocks[j - 2];
|
||||||
|
s1 = ((t1 >>> 17) | (t1 << 15)) ^ ((t1 >>> 19) | (t1 << 13)) ^ (t1 >>> 10);
|
||||||
|
blocks[j] = blocks[j - 16] + s0 + blocks[j - 7] + s1 << 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bc = b & c;
|
||||||
|
for (j = 0; j < 64; j += 4) {
|
||||||
|
if (this.first) {
|
||||||
|
if (this.is224) {
|
||||||
|
ab = 300032;
|
||||||
|
t1 = blocks[0] - 1413257819;
|
||||||
|
h = t1 - 150054599 << 0;
|
||||||
|
d = t1 + 24177077 << 0;
|
||||||
|
} else {
|
||||||
|
ab = 704751109;
|
||||||
|
t1 = blocks[0] - 210244248;
|
||||||
|
h = t1 - 1521486534 << 0;
|
||||||
|
d = t1 + 143694565 << 0;
|
||||||
|
}
|
||||||
|
this.first = false;
|
||||||
|
} else {
|
||||||
|
s0 = ((a >>> 2) | (a << 30)) ^ ((a >>> 13) | (a << 19)) ^ ((a >>> 22) | (a << 10));
|
||||||
|
s1 = ((e >>> 6) | (e << 26)) ^ ((e >>> 11) | (e << 21)) ^ ((e >>> 25) | (e << 7));
|
||||||
|
ab = a & b;
|
||||||
|
maj = ab ^ (a & c) ^ bc;
|
||||||
|
ch = (e & f) ^ (~e & g);
|
||||||
|
t1 = h + s1 + ch + K[j] + blocks[j];
|
||||||
|
t2 = s0 + maj;
|
||||||
|
h = d + t1 << 0;
|
||||||
|
d = t1 + t2 << 0;
|
||||||
|
}
|
||||||
|
s0 = ((d >>> 2) | (d << 30)) ^ ((d >>> 13) | (d << 19)) ^ ((d >>> 22) | (d << 10));
|
||||||
|
s1 = ((h >>> 6) | (h << 26)) ^ ((h >>> 11) | (h << 21)) ^ ((h >>> 25) | (h << 7));
|
||||||
|
da = d & a;
|
||||||
|
maj = da ^ (d & b) ^ ab;
|
||||||
|
ch = (h & e) ^ (~h & f);
|
||||||
|
t1 = g + s1 + ch + K[j + 1] + blocks[j + 1];
|
||||||
|
t2 = s0 + maj;
|
||||||
|
g = c + t1 << 0;
|
||||||
|
c = t1 + t2 << 0;
|
||||||
|
s0 = ((c >>> 2) | (c << 30)) ^ ((c >>> 13) | (c << 19)) ^ ((c >>> 22) | (c << 10));
|
||||||
|
s1 = ((g >>> 6) | (g << 26)) ^ ((g >>> 11) | (g << 21)) ^ ((g >>> 25) | (g << 7));
|
||||||
|
cd = c & d;
|
||||||
|
maj = cd ^ (c & a) ^ da;
|
||||||
|
ch = (g & h) ^ (~g & e);
|
||||||
|
t1 = f + s1 + ch + K[j + 2] + blocks[j + 2];
|
||||||
|
t2 = s0 + maj;
|
||||||
|
f = b + t1 << 0;
|
||||||
|
b = t1 + t2 << 0;
|
||||||
|
s0 = ((b >>> 2) | (b << 30)) ^ ((b >>> 13) | (b << 19)) ^ ((b >>> 22) | (b << 10));
|
||||||
|
s1 = ((f >>> 6) | (f << 26)) ^ ((f >>> 11) | (f << 21)) ^ ((f >>> 25) | (f << 7));
|
||||||
|
bc = b & c;
|
||||||
|
maj = bc ^ (b & d) ^ cd;
|
||||||
|
ch = (f & g) ^ (~f & h);
|
||||||
|
t1 = e + s1 + ch + K[j + 3] + blocks[j + 3];
|
||||||
|
t2 = s0 + maj;
|
||||||
|
e = a + t1 << 0;
|
||||||
|
a = t1 + t2 << 0;
|
||||||
|
this.chromeBugWorkAround = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.h0 = this.h0 + a << 0;
|
||||||
|
this.h1 = this.h1 + b << 0;
|
||||||
|
this.h2 = this.h2 + c << 0;
|
||||||
|
this.h3 = this.h3 + d << 0;
|
||||||
|
this.h4 = this.h4 + e << 0;
|
||||||
|
this.h5 = this.h5 + f << 0;
|
||||||
|
this.h6 = this.h6 + g << 0;
|
||||||
|
this.h7 = this.h7 + h << 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sha256.prototype.hex = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5,
|
||||||
|
h6 = this.h6, h7 = this.h7;
|
||||||
|
|
||||||
|
var hex = HEX_CHARS[(h0 >>> 28) & 0x0F] + HEX_CHARS[(h0 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h0 >>> 20) & 0x0F] + HEX_CHARS[(h0 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h0 >>> 12) & 0x0F] + HEX_CHARS[(h0 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h0 >>> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] +
|
||||||
|
HEX_CHARS[(h1 >>> 28) & 0x0F] + HEX_CHARS[(h1 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h1 >>> 20) & 0x0F] + HEX_CHARS[(h1 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h1 >>> 12) & 0x0F] + HEX_CHARS[(h1 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h1 >>> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] +
|
||||||
|
HEX_CHARS[(h2 >>> 28) & 0x0F] + HEX_CHARS[(h2 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h2 >>> 20) & 0x0F] + HEX_CHARS[(h2 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h2 >>> 12) & 0x0F] + HEX_CHARS[(h2 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h2 >>> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] +
|
||||||
|
HEX_CHARS[(h3 >>> 28) & 0x0F] + HEX_CHARS[(h3 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h3 >>> 20) & 0x0F] + HEX_CHARS[(h3 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h3 >>> 12) & 0x0F] + HEX_CHARS[(h3 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h3 >>> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] +
|
||||||
|
HEX_CHARS[(h4 >>> 28) & 0x0F] + HEX_CHARS[(h4 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h4 >>> 20) & 0x0F] + HEX_CHARS[(h4 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h4 >>> 12) & 0x0F] + HEX_CHARS[(h4 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h4 >>> 4) & 0x0F] + HEX_CHARS[h4 & 0x0F] +
|
||||||
|
HEX_CHARS[(h5 >>> 28) & 0x0F] + HEX_CHARS[(h5 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h5 >>> 20) & 0x0F] + HEX_CHARS[(h5 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h5 >>> 12) & 0x0F] + HEX_CHARS[(h5 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h5 >>> 4) & 0x0F] + HEX_CHARS[h5 & 0x0F] +
|
||||||
|
HEX_CHARS[(h6 >>> 28) & 0x0F] + HEX_CHARS[(h6 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h6 >>> 20) & 0x0F] + HEX_CHARS[(h6 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h6 >>> 12) & 0x0F] + HEX_CHARS[(h6 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h6 >>> 4) & 0x0F] + HEX_CHARS[h6 & 0x0F];
|
||||||
|
if (!this.is224) {
|
||||||
|
hex += HEX_CHARS[(h7 >>> 28) & 0x0F] + HEX_CHARS[(h7 >>> 24) & 0x0F] +
|
||||||
|
HEX_CHARS[(h7 >>> 20) & 0x0F] + HEX_CHARS[(h7 >>> 16) & 0x0F] +
|
||||||
|
HEX_CHARS[(h7 >>> 12) & 0x0F] + HEX_CHARS[(h7 >>> 8) & 0x0F] +
|
||||||
|
HEX_CHARS[(h7 >>> 4) & 0x0F] + HEX_CHARS[h7 & 0x0F];
|
||||||
|
}
|
||||||
|
return hex;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sha256.prototype.toString = Sha256.prototype.hex;
|
||||||
|
|
||||||
|
Sha256.prototype.digest = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3, h4 = this.h4, h5 = this.h5,
|
||||||
|
h6 = this.h6, h7 = this.h7;
|
||||||
|
|
||||||
|
var arr = [
|
||||||
|
(h0 >>> 24) & 0xFF, (h0 >>> 16) & 0xFF, (h0 >>> 8) & 0xFF, h0 & 0xFF,
|
||||||
|
(h1 >>> 24) & 0xFF, (h1 >>> 16) & 0xFF, (h1 >>> 8) & 0xFF, h1 & 0xFF,
|
||||||
|
(h2 >>> 24) & 0xFF, (h2 >>> 16) & 0xFF, (h2 >>> 8) & 0xFF, h2 & 0xFF,
|
||||||
|
(h3 >>> 24) & 0xFF, (h3 >>> 16) & 0xFF, (h3 >>> 8) & 0xFF, h3 & 0xFF,
|
||||||
|
(h4 >>> 24) & 0xFF, (h4 >>> 16) & 0xFF, (h4 >>> 8) & 0xFF, h4 & 0xFF,
|
||||||
|
(h5 >>> 24) & 0xFF, (h5 >>> 16) & 0xFF, (h5 >>> 8) & 0xFF, h5 & 0xFF,
|
||||||
|
(h6 >>> 24) & 0xFF, (h6 >>> 16) & 0xFF, (h6 >>> 8) & 0xFF, h6 & 0xFF
|
||||||
|
];
|
||||||
|
if (!this.is224) {
|
||||||
|
arr.push((h7 >>> 24) & 0xFF, (h7 >>> 16) & 0xFF, (h7 >>> 8) & 0xFF, h7 & 0xFF);
|
||||||
|
}
|
||||||
|
return arr;
|
||||||
|
};
|
||||||
|
|
||||||
|
Sha256.prototype.array = Sha256.prototype.digest;
|
||||||
|
|
||||||
|
Sha256.prototype.arrayBuffer = function () {
|
||||||
|
this.finalize();
|
||||||
|
|
||||||
|
var buffer = new ArrayBuffer(this.is224 ? 28 : 32);
|
||||||
|
var dataView = new DataView(buffer);
|
||||||
|
dataView.setUint32(0, this.h0);
|
||||||
|
dataView.setUint32(4, this.h1);
|
||||||
|
dataView.setUint32(8, this.h2);
|
||||||
|
dataView.setUint32(12, this.h3);
|
||||||
|
dataView.setUint32(16, this.h4);
|
||||||
|
dataView.setUint32(20, this.h5);
|
||||||
|
dataView.setUint32(24, this.h6);
|
||||||
|
if (!this.is224) {
|
||||||
|
dataView.setUint32(28, this.h7);
|
||||||
|
}
|
||||||
|
return buffer;
|
||||||
|
};
|
||||||
|
|
||||||
|
function HmacSha256(key, is224, sharedMemory) {
|
||||||
|
var i, type = typeof key;
|
||||||
|
if (type === 'string') {
|
||||||
|
var bytes = [], length = key.length, index = 0, code;
|
||||||
|
for (i = 0; i < length; ++i) {
|
||||||
|
code = key.charCodeAt(i);
|
||||||
|
if (code < 0x80) {
|
||||||
|
bytes[index++] = code;
|
||||||
|
} else if (code < 0x800) {
|
||||||
|
bytes[index++] = (0xc0 | (code >>> 6));
|
||||||
|
bytes[index++] = (0x80 | (code & 0x3f));
|
||||||
|
} else if (code < 0xd800 || code >= 0xe000) {
|
||||||
|
bytes[index++] = (0xe0 | (code >>> 12));
|
||||||
|
bytes[index++] = (0x80 | ((code >>> 6) & 0x3f));
|
||||||
|
bytes[index++] = (0x80 | (code & 0x3f));
|
||||||
|
} else {
|
||||||
|
code = 0x10000 + (((code & 0x3ff) << 10) | (key.charCodeAt(++i) & 0x3ff));
|
||||||
|
bytes[index++] = (0xf0 | (code >>> 18));
|
||||||
|
bytes[index++] = (0x80 | ((code >>> 12) & 0x3f));
|
||||||
|
bytes[index++] = (0x80 | ((code >>> 6) & 0x3f));
|
||||||
|
bytes[index++] = (0x80 | (code & 0x3f));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
key = bytes;
|
||||||
|
} else {
|
||||||
|
if (type === 'object') {
|
||||||
|
if (key === null) {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
} else if (ARRAY_BUFFER && key.constructor === ArrayBuffer) {
|
||||||
|
key = new Uint8Array(key);
|
||||||
|
} else if (!Array.isArray(key)) {
|
||||||
|
if (!ARRAY_BUFFER || !ArrayBuffer.isView(key)) {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(ERROR);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key.length > 64) {
|
||||||
|
key = (new Sha256(is224, true)).update(key).array();
|
||||||
|
}
|
||||||
|
|
||||||
|
var oKeyPad = [], iKeyPad = [];
|
||||||
|
for (i = 0; i < 64; ++i) {
|
||||||
|
var b = key[i] || 0;
|
||||||
|
oKeyPad[i] = 0x5c ^ b;
|
||||||
|
iKeyPad[i] = 0x36 ^ b;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sha256.call(this, is224, sharedMemory);
|
||||||
|
|
||||||
|
this.update(iKeyPad);
|
||||||
|
this.oKeyPad = oKeyPad;
|
||||||
|
this.inner = true;
|
||||||
|
this.sharedMemory = sharedMemory;
|
||||||
|
}
|
||||||
|
HmacSha256.prototype = new Sha256();
|
||||||
|
|
||||||
|
HmacSha256.prototype.finalize = function () {
|
||||||
|
Sha256.prototype.finalize.call(this);
|
||||||
|
if (this.inner) {
|
||||||
|
this.inner = false;
|
||||||
|
var innerHash = this.array();
|
||||||
|
Sha256.call(this, this.is224, this.sharedMemory);
|
||||||
|
this.update(this.oKeyPad);
|
||||||
|
this.update(innerHash);
|
||||||
|
Sha256.prototype.finalize.call(this);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var exports = createMethod();
|
||||||
|
exports.sha256 = exports;
|
||||||
|
exports.sha224 = createMethod(true);
|
||||||
|
exports.sha256.hmac = createHmacMethod();
|
||||||
|
exports.sha224.hmac = createHmacMethod(true);
|
||||||
|
|
||||||
|
if (COMMON_JS) {
|
||||||
|
module.exports = exports;
|
||||||
|
} else {
|
||||||
|
root.sha256 = exports.sha256;
|
||||||
|
root.sha224 = exports.sha224;
|
||||||
|
if (AMD) {
|
||||||
|
define(function () {
|
||||||
|
return exports;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})();
|
||||||
Reference in New Issue
Block a user