From 9f838e934f2956add910f89e6459a59245d5b472 Mon Sep 17 00:00:00 2001
From: Shxde <112267394+Shxde1@users.noreply.github.com>
Date: Sat, 21 Dec 2024 13:14:13 -0500
Subject: [PATCH] Add files via upload
---
QRCode/pingout.cpp | 213 +
QRCode/pngout.hpp | 98 +
QRCode/qr.png.cpp | 125 +
QRCode/qr.png.h | 71 +
QRCode/qrcode.cpp | 831 ++
QRCode/qrcode.hpp | 549 +
README.md | 37 +-
Security.hpp | 106 +
auth.cpp | 2074 ++++
auth.hpp | 164 +
curl/Makefile.am | 39 +
curl/Makefile.in | 702 ++
curl/curl.h | 3260 ++++++
curl/curlver.h | 79 +
curl/easy.h | 125 +
curl/header.h | 74 +
curl/libcurl.lib | Bin 0 -> 15192174 bytes
curl/mprintf.h | 85 +
curl/multi.h | 485 +
curl/options.h | 70 +
curl/stdcheaders.h | 35 +
curl/system.h | 496 +
curl/typecheck-gcc.h | 718 ++
curl/urlapi.h | 155 +
curl/websockets.h | 84 +
curl/zlib.lib | Bin 0 -> 461752 bytes
includes.hpp | 18 +
killEmulator.hpp | 109 +
lazy_importer.hpp | 723 ++
library.sln | 25 +
library.vcxproj | 316 +
library.vcxproj.filters | 441 +
library.vcxproj.user | 6 +
nlohmann/adl_serializer.hpp | 49 +
nlohmann/byte_container_with_subtype.hpp | 166 +
nlohmann/detail/conversions/from_json.hpp | 403 +
nlohmann/detail/conversions/to_chars.hpp | 1105 +++
nlohmann/detail/conversions/to_json.hpp | 374 +
nlohmann/detail/exceptions.hpp | 357 +
nlohmann/detail/hash.hpp | 117 +
nlohmann/detail/input/binary_reader.hpp | 2459 +++++
nlohmann/detail/input/input_adapters.hpp | 454 +
nlohmann/detail/input/json_sax.hpp | 696 ++
nlohmann/detail/input/lexer.hpp | 1623 +++
nlohmann/detail/input/parser.hpp | 501 +
nlohmann/detail/input/position_t.hpp | 27 +
.../detail/iterators/internal_iterator.hpp | 25 +
nlohmann/detail/iterators/iter_impl.hpp | 637 ++
nlohmann/detail/iterators/iteration_proxy.hpp | 178 +
nlohmann/detail/iterators/iterator_traits.hpp | 51 +
.../iterators/json_reverse_iterator.hpp | 119 +
.../detail/iterators/primitive_iterator.hpp | 120 +
nlohmann/detail/json_pointer.hpp | 975 ++
nlohmann/detail/json_ref.hpp | 76 +
nlohmann/detail/macro_scope.hpp | 297 +
nlohmann/detail/macro_unscope.hpp | 23 +
nlohmann/detail/meta/cpp_future.hpp | 62 +
nlohmann/detail/meta/detected.hpp | 58 +
nlohmann/detail/meta/is_sax.hpp | 149 +
nlohmann/detail/meta/type_traits.hpp | 396 +
nlohmann/detail/meta/void_t.hpp | 13 +
nlohmann/detail/output/binary_writer.hpp | 1595 +++
nlohmann/detail/output/output_adapters.hpp | 123 +
nlohmann/detail/output/serializer.hpp | 947 ++
nlohmann/detail/value_t.hpp | 81 +
nlohmann/json.hpp | 8791 +++++++++++++++++
nlohmann/json_fwd.hpp | 78 +
nlohmann/ordered_map.hpp | 171 +
nlohmann/thirdparty/hedley/hedley.hpp | 1911 ++++
nlohmann/thirdparty/hedley/hedley_undef.hpp | 143 +
utils.cpp | 26 +
utils.hpp | 10 +
xorstr.hpp | 157 +
73 files changed, 37839 insertions(+), 17 deletions(-)
create mode 100644 QRCode/pingout.cpp
create mode 100644 QRCode/pngout.hpp
create mode 100644 QRCode/qr.png.cpp
create mode 100644 QRCode/qr.png.h
create mode 100644 QRCode/qrcode.cpp
create mode 100644 QRCode/qrcode.hpp
create mode 100644 Security.hpp
create mode 100644 auth.cpp
create mode 100644 auth.hpp
create mode 100644 curl/Makefile.am
create mode 100644 curl/Makefile.in
create mode 100644 curl/curl.h
create mode 100644 curl/curlver.h
create mode 100644 curl/easy.h
create mode 100644 curl/header.h
create mode 100644 curl/libcurl.lib
create mode 100644 curl/mprintf.h
create mode 100644 curl/multi.h
create mode 100644 curl/options.h
create mode 100644 curl/stdcheaders.h
create mode 100644 curl/system.h
create mode 100644 curl/typecheck-gcc.h
create mode 100644 curl/urlapi.h
create mode 100644 curl/websockets.h
create mode 100644 curl/zlib.lib
create mode 100644 includes.hpp
create mode 100644 killEmulator.hpp
create mode 100644 lazy_importer.hpp
create mode 100644 library.sln
create mode 100644 library.vcxproj
create mode 100644 library.vcxproj.filters
create mode 100644 library.vcxproj.user
create mode 100644 nlohmann/adl_serializer.hpp
create mode 100644 nlohmann/byte_container_with_subtype.hpp
create mode 100644 nlohmann/detail/conversions/from_json.hpp
create mode 100644 nlohmann/detail/conversions/to_chars.hpp
create mode 100644 nlohmann/detail/conversions/to_json.hpp
create mode 100644 nlohmann/detail/exceptions.hpp
create mode 100644 nlohmann/detail/hash.hpp
create mode 100644 nlohmann/detail/input/binary_reader.hpp
create mode 100644 nlohmann/detail/input/input_adapters.hpp
create mode 100644 nlohmann/detail/input/json_sax.hpp
create mode 100644 nlohmann/detail/input/lexer.hpp
create mode 100644 nlohmann/detail/input/parser.hpp
create mode 100644 nlohmann/detail/input/position_t.hpp
create mode 100644 nlohmann/detail/iterators/internal_iterator.hpp
create mode 100644 nlohmann/detail/iterators/iter_impl.hpp
create mode 100644 nlohmann/detail/iterators/iteration_proxy.hpp
create mode 100644 nlohmann/detail/iterators/iterator_traits.hpp
create mode 100644 nlohmann/detail/iterators/json_reverse_iterator.hpp
create mode 100644 nlohmann/detail/iterators/primitive_iterator.hpp
create mode 100644 nlohmann/detail/json_pointer.hpp
create mode 100644 nlohmann/detail/json_ref.hpp
create mode 100644 nlohmann/detail/macro_scope.hpp
create mode 100644 nlohmann/detail/macro_unscope.hpp
create mode 100644 nlohmann/detail/meta/cpp_future.hpp
create mode 100644 nlohmann/detail/meta/detected.hpp
create mode 100644 nlohmann/detail/meta/is_sax.hpp
create mode 100644 nlohmann/detail/meta/type_traits.hpp
create mode 100644 nlohmann/detail/meta/void_t.hpp
create mode 100644 nlohmann/detail/output/binary_writer.hpp
create mode 100644 nlohmann/detail/output/output_adapters.hpp
create mode 100644 nlohmann/detail/output/serializer.hpp
create mode 100644 nlohmann/detail/value_t.hpp
create mode 100644 nlohmann/json.hpp
create mode 100644 nlohmann/json_fwd.hpp
create mode 100644 nlohmann/ordered_map.hpp
create mode 100644 nlohmann/thirdparty/hedley/hedley.hpp
create mode 100644 nlohmann/thirdparty/hedley/hedley_undef.hpp
create mode 100644 utils.cpp
create mode 100644 utils.hpp
create mode 100644 xorstr.hpp
diff --git a/QRCode/pingout.cpp b/QRCode/pingout.cpp
new file mode 100644
index 0000000..ea357ad
--- /dev/null
+++ b/QRCode/pingout.cpp
@@ -0,0 +1,213 @@
+/*
+ * Tiny PNG Output (C++)
+ *
+ * Copyright (c) 2018 Project Nayuki
+ * https://www.nayuki.io/page/tiny-png-output
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program (see COPYING.txt and COPYING.LESSER.txt).
+ * If not, see .
+ */
+
+#pragma warning(disable:4146)
+
+#include
+#include
+#include
+#include
+#include "pngout.hpp"
+
+#pragma warning(disable:C4146)
+
+using std::uint8_t;
+using std::uint16_t;
+using std::uint32_t;
+using std::uint64_t;
+using std::size_t;
+
+
+TinyPngOut::TinyPngOut(uint32_t w, uint32_t h, std::ostream &out) :
+ // Set most of the fields
+ width(w),
+ height(h),
+ output(out),
+ positionX(0),
+ positionY(0),
+ deflateFilled(0),
+ adler(1) {
+
+ // Check arguments
+ if (width == 0 || height == 0)
+ throw std::domain_error("Zero width or height");
+
+ // Compute and check data siezs
+ uint64_t lineSz = static_cast(width) * 3 + 1;
+ if (lineSz > UINT32_MAX)
+ throw std::length_error("Image too large");
+ lineSize = static_cast(lineSz);
+
+ uint64_t uncompRm = lineSize * height;
+ if (uncompRm > UINT32_MAX)
+ throw std::length_error("Image too large");
+ uncompRemain = static_cast(uncompRm);
+
+ uint32_t numBlocks = uncompRemain / DEFLATE_MAX_BLOCK_SIZE;
+ if (uncompRemain % DEFLATE_MAX_BLOCK_SIZE != 0)
+ numBlocks++; // Round up
+ // 5 bytes per DEFLATE uncompressed block header, 2 bytes for zlib header, 4 bytes for zlib Adler-32 footer
+ uint64_t idatSize = static_cast(numBlocks) * 5 + 6;
+ idatSize += uncompRemain;
+ if (idatSize > static_cast(INT32_MAX))
+ throw std::length_error("Image too large");
+
+ // Write header (not a pure header, but a couple of things concatenated together)
+ uint8_t header[] = { // 43 bytes long
+ // PNG header
+ 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A,
+ // IHDR chunk
+ 0x00, 0x00, 0x00, 0x0D,
+ 0x49, 0x48, 0x44, 0x52,
+ 0, 0, 0, 0, // 'width' placeholder
+ 0, 0, 0, 0, // 'height' placeholder
+ 0x08, 0x02, 0x00, 0x00, 0x00,
+ 0, 0, 0, 0, // IHDR CRC-32 placeholder
+ // IDAT chunk
+ 0, 0, 0, 0, // 'idatSize' placeholder
+ 0x49, 0x44, 0x41, 0x54,
+ // DEFLATE data
+ 0x08, 0x1D,
+ };
+ putBigUint32(width, &header[16]);
+ putBigUint32(height, &header[20]);
+ putBigUint32(idatSize, &header[33]);
+ crc = 0;
+ crc32(&header[12], 17);
+ putBigUint32(crc, &header[29]);
+ write(header);
+
+ crc = 0;
+ crc32(&header[37], 6); // 0xD7245B6B
+}
+
+
+void TinyPngOut::write(const uint8_t pixels[], size_t count) {
+ if (count > SIZE_MAX / 3)
+ throw std::length_error("Invalid argument");
+ count *= 3; // Convert pixel count to byte count
+ while (count > 0) {
+ if (pixels == nullptr)
+ throw std::invalid_argument("Null pointer");
+ if (positionY >= height)
+ throw std::logic_error("All image pixels already written");
+
+ if (deflateFilled == 0) { // Start DEFLATE block
+ uint16_t size = DEFLATE_MAX_BLOCK_SIZE;
+ if (uncompRemain < size)
+ size = static_cast(uncompRemain);
+ const uint8_t header[] = { // 5 bytes long
+ static_cast(uncompRemain <= DEFLATE_MAX_BLOCK_SIZE ? 1 : 0),
+ static_cast(size >> 0),
+ static_cast(size >> 8),
+ static_cast((size >> 0) ^ 0xFF),
+ static_cast((size >> 8) ^ 0xFF),
+ };
+ write(header);
+ crc32(header, sizeof(header) / sizeof(header[0]));
+ }
+ assert(positionX < lineSize && deflateFilled < DEFLATE_MAX_BLOCK_SIZE);
+
+ if (positionX == 0) { // Beginning of line - write filter method byte
+ uint8_t b[] = {0};
+ write(b);
+ crc32(b, 1);
+ adler32(b, 1);
+ positionX++;
+ uncompRemain--;
+ deflateFilled++;
+
+ } else { // Write some pixel bytes for current line
+ uint16_t n = DEFLATE_MAX_BLOCK_SIZE - deflateFilled;
+ if (lineSize - positionX < n)
+ n = static_cast(lineSize - positionX);
+ if (count < n)
+ n = static_cast(count);
+ if (static_cast::type>(std::numeric_limits::max()) < std::numeric_limits::max())
+ n = std::min(n, static_cast(std::numeric_limits::max()));
+ assert(n > 0);
+ output.write(reinterpret_cast(pixels), static_cast(n));
+
+ // Update checksums
+ crc32(pixels, n);
+ adler32(pixels, n);
+
+ // Increment positions
+ count -= n;
+ pixels += n;
+ positionX += n;
+ uncompRemain -= n;
+ deflateFilled += n;
+ }
+
+ if (deflateFilled >= DEFLATE_MAX_BLOCK_SIZE)
+ deflateFilled = 0; // End current block
+
+ if (positionX == lineSize) { // Increment line
+ positionX = 0;
+ positionY++;
+ if (positionY == height) { // Reached end of pixels
+ uint8_t footer[] = { // 20 bytes long
+ 0, 0, 0, 0, // DEFLATE Adler-32 placeholder
+ 0, 0, 0, 0, // IDAT CRC-32 placeholder
+ // IEND chunk
+ 0x00, 0x00, 0x00, 0x00,
+ 0x49, 0x45, 0x4E, 0x44,
+ 0xAE, 0x42, 0x60, 0x82,
+ };
+ putBigUint32(adler, &footer[0]);
+ crc32(&footer[0], 4);
+ putBigUint32(crc, &footer[4]);
+ write(footer);
+ }
+ }
+ }
+}
+
+
+void TinyPngOut::crc32(const uint8_t data[], size_t len) {
+ crc = ~crc;
+ for (size_t i = 0; i < len; i++) {
+ for (int j = 0; j < 8; j++) { // Inefficient bitwise implementation, instead of table-based
+ uint32_t bit = (crc ^ (data[i] >> j)) & 1;
+ crc = (crc >> 1) ^ ((-bit) & UINT32_C(0xEDB88320));
+ }
+ }
+ crc = ~crc;
+}
+
+
+void TinyPngOut::adler32(const uint8_t data[], size_t len) {
+ uint32_t s1 = adler & 0xFFFF;
+ uint32_t s2 = adler >> 16;
+ for (size_t i = 0; i < len; i++) {
+ s1 = (s1 + data[i]) % 65521;
+ s2 = (s2 + s1) % 65521;
+ }
+ adler = s2 << 16 | s1;
+}
+
+
+void TinyPngOut::putBigUint32(uint32_t val, uint8_t array[4]) {
+ for (int i = 0; i < 4; i++)
+ array[i] = static_cast(val >> ((3 - i) * 8));
+}
+
diff --git a/QRCode/pngout.hpp b/QRCode/pngout.hpp
new file mode 100644
index 0000000..2f2c5a3
--- /dev/null
+++ b/QRCode/pngout.hpp
@@ -0,0 +1,98 @@
+/*
+ * Tiny PNG Output (C++)
+ *
+ * Copyright (c) 2018 Project Nayuki
+ * https://www.nayuki.io/page/tiny-png-output
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program (see COPYING.txt and COPYING.LESSER.txt).
+ * If not, see .
+ */
+
+#pragma once
+
+#include
+#include
+#include
+
+
+/*
+ * Takes image pixel data in raw RGB8.8.8 format and writes a PNG file to a byte output stream.
+ */
+class TinyPngOut final {
+
+ /*---- Fields ----*/
+
+ // Immutable configuration
+ private: std::uint32_t width; // Measured in pixels
+ private: std::uint32_t height; // Measured in pixels
+ private: std::uint32_t lineSize; // Measured in bytes, equal to (width * 3 + 1)
+
+ // Running state
+ private: std::ostream &output;
+ private: std::uint32_t positionX; // Next byte index in current line
+ private: std::uint32_t positionY; // Line index of next byte
+ private: std::uint32_t uncompRemain; // Number of uncompressed bytes remaining
+ private: std::uint16_t deflateFilled; // Bytes filled in the current block (0 <= n < DEFLATE_MAX_BLOCK_SIZE)
+ private: std::uint32_t crc; // Primarily for IDAT chunk
+ private: std::uint32_t adler; // For DEFLATE data within IDAT
+
+
+
+ /*---- Public constructor and method ----*/
+
+ /*
+ * Creates a PNG writer with the given width and height (both non-zero) and byte output stream.
+ * TinyPngOut will leave the output stream still open once it finishes writing the PNG file data.
+ * Throws an exception if the dimensions exceed certain limits (e.g. w * h > 700 million).
+ */
+ public: explicit TinyPngOut(std::uint32_t w, std::uint32_t h, std::ostream &out);
+
+
+ /*
+ * Writes 'count' pixels from the given array to the output stream. This reads count*3
+ * bytes from the array. Pixels are presented from top to bottom, left to right, and with
+ * subpixels in RGB order. This object keeps track of how many pixels were written and
+ * various position variables. It is an error to write more pixels in total than width*height.
+ * Once exactly width*height pixels have been written with this TinyPngOut object,
+ * there are no more valid operations on the object and it should be discarded.
+ */
+ public: void write(const std::uint8_t pixels[], size_t count);
+
+
+
+ /*---- Private checksum methods ----*/
+
+ // Reads the 'crc' field and updates its value based on the given array of new data.
+ private: void crc32(const std::uint8_t data[], size_t len);
+
+
+ // Reads the 'adler' field and updates its value based on the given array of new data.
+ private: void adler32(const std::uint8_t data[], size_t len);
+
+
+
+ /*---- Private utility members ----*/
+
+ private: template
+ void write(const std::uint8_t (&data)[N]) {
+ output.write(reinterpret_cast(data), sizeof(data));
+ }
+
+
+ private: static void putBigUint32(std::uint32_t val, std::uint8_t array[4]);
+
+
+ private: static constexpr std::uint16_t DEFLATE_MAX_BLOCK_SIZE = 65535;
+
+};
diff --git a/QRCode/qr.png.cpp b/QRCode/qr.png.cpp
new file mode 100644
index 0000000..c9c6e6f
--- /dev/null
+++ b/QRCode/qr.png.cpp
@@ -0,0 +1,125 @@
+//
+// Created by remy on 02-06-20.
+//
+
+#include "qr.png.h"
+#include "pngout.hpp"
+
+QrToPng::QrToPng(std::string fileName, int imgSize, int minModulePixelSize, std::string text,
+ bool overwriteExistingFile, qrcodegen::QrCode::Ecc ecc) :
+ _fileName(std::move(fileName)), _size(imgSize), _minModulePixelSize(minModulePixelSize), _text(std::move(text)),
+ _overwriteExistingFile(overwriteExistingFile), _ecc(ecc) {
+}
+
+bool QrToPng::writeToPNG() {
+ /* text is required */
+ if (_text.empty())
+ return false;
+
+
+ if (!_overwriteExistingFile and fs::exists(_fileName))
+ return false;
+
+ auto _qr = qrcodegen::QrCode::encodeText("", _ecc);
+ try {
+ _qr = qrcodegen::QrCode::encodeText(_text.c_str(), _ecc);
+ }
+ catch (const std::length_error &e) {
+ std::cerr << "Failed to generate QR code, too much data. Decrease _ecc, enlarge size or give less text."
+ << std::endl;
+ std::cerr << "e.what(): " << e.what() << std::endl;
+ return false;
+ }
+
+ if (_overwriteExistingFile and fs::exists(_fileName))
+ if (!fs::copy_file(_fileName, _fileName + ".tmp", fs::copy_options::overwrite_existing))
+ return false;
+
+ auto result = _writeToPNG(_qr);
+
+ if (result)
+ fs::remove(_fileName + ".tmp");
+
+ return result;
+
+}
+
+bool QrToPng::_writeToPNG(const qrcodegen::QrCode &qrData) const {
+ std::ofstream out(_fileName.c_str(), std::ios::binary);
+ int pngWH = _imgSizeWithBorder(qrData);
+ TinyPngOut pngout(pngWH, pngWH, out);
+
+ auto qrSize = qrData.getSize();
+ auto qrSizeWithBorder = qrData.getSize() + 2;
+ if (qrSizeWithBorder > _size)
+ return false; // qrcode doesn't fit
+
+ int qrSizeFitsInMaxImgSizeTimes = _size / qrSizeWithBorder;
+ int pixelsWHPerModule = qrSizeFitsInMaxImgSizeTimes;
+
+ if (qrSizeFitsInMaxImgSizeTimes < _minModulePixelSize)
+ return false; // image would be to small to scan
+
+ std::vector tmpData;
+ const uint8_t blackPixel = 0x00;
+ const uint8_t whitePixel = 0xFF;
+
+ /* The below loop converts the qrData to RGB8.8.8 pixels and writes it with
+ * the tinyPNGoutput library. since we probably have requested a larger
+ * qr module pixel size we must transform the qrData modules to be larger
+ * pixels (than just 1x1). */
+
+ // border above
+ for (int i = 0; i < pngWH; i++) // row
+ for (int j = 0; j < pixelsWHPerModule; j++) // module pixel (height)
+ tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel});
+
+ pngout.write(tmpData.data(), static_cast(tmpData.size() / 3));
+ tmpData.clear();
+
+ for (int qrModuleAtY = 0; qrModuleAtY < qrSize; qrModuleAtY++) {
+ for (int col = 0; col < pixelsWHPerModule; col++) {
+ // border left
+ for (int i = 0; i < qrSizeFitsInMaxImgSizeTimes; ++i)
+ tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel});
+
+ // qr module to pixel
+ for (int qrModuleAtX = 0; qrModuleAtX < (qrSize); qrModuleAtX++) {
+ for (int row = 0; row < qrSizeFitsInMaxImgSizeTimes; ++row) {
+ if (qrData.getModule(qrModuleAtX, qrModuleAtY)) {
+ // insert saves us a for loop or 3 times the same line.
+ tmpData.insert(tmpData.end(), {blackPixel, blackPixel, blackPixel});
+ } else {
+ tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel});
+ }
+ }
+ }
+ // border right
+ for (int i = 0; i < qrSizeFitsInMaxImgSizeTimes; ++i)
+ tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel});
+
+ // write the entire row
+ pngout.write(tmpData.data(), static_cast(tmpData.size() / 3));
+ tmpData.clear();
+ }
+ }
+
+ // border below
+ for (int i = 0; i < pngWH; i++) // row
+ for (int j = 0; j < pixelsWHPerModule; j++) // module pixel (height)
+ tmpData.insert(tmpData.end(), {whitePixel, whitePixel, whitePixel});
+
+ pngout.write(tmpData.data(), static_cast(tmpData.size() / 3));
+ tmpData.clear();
+
+ return fs::exists(_fileName);
+}
+
+
+uint32_t QrToPng::_imgSize(const qrcodegen::QrCode &qrData) const {
+ return (_size / qrData.getSize()) * qrData.getSize();
+}
+
+uint32_t QrToPng::_imgSizeWithBorder(const qrcodegen::QrCode &qrData) const {
+ return (_size / (qrData.getSize() + 2)) * (qrData.getSize() + 2);
+}
\ No newline at end of file
diff --git a/QRCode/qr.png.h b/QRCode/qr.png.h
new file mode 100644
index 0000000..c8a8d9a
--- /dev/null
+++ b/QRCode/qr.png.h
@@ -0,0 +1,71 @@
+//
+// Created by remy on 07-06-20.
+//
+
+#ifndef QR_TO_PNG_H
+#define QR_TO_PNG_H
+
+/* If your compiler is recent enough,
+ * you don't need to include '::experimental::',
+ * you can just include "::filesystem". The below
+ * code makes both work, accessible at 'fs::'. */
+#if defined(__GNUC__) && __GNUC__ < 9
+#include
+namespace fs = std::experimental::filesystem;
+#else
+#include
+namespace fs = std::filesystem;
+#endif
+
+#include "QrCode.hpp"
+#include "qrcode.hpp"
+#include
+#include
+#include
+#include
+
+class QrToPng {
+public:
+ /**
+ * Gives an object containing all the data to create the QR code. When @writeToPNG() is called,
+ * the actual file is constructed and written.
+ * The image is scaled to fit in the given size as much as possible relative to the QR code
+ * size.
+ * @param fileName relative or absolute filename to write image to. Relative will be in CWD.
+ * @param imgSize The height and width of the image. Image is square, so will be width and height.
+ * @param minModulePixelSize How many pixels big should a qr module be (a white or black dot)?
+ * @param text The text to encode in the QR code.
+ * @param overwriteExistingFile Overwrite if a file with @fileName already exists?
+ * @param ecc error correction (low,mid,high).
+ */
+ QrToPng(std::string fileName, int imgSize, int minModulePixelSize, std::string text,
+ bool overwriteExistingFile, qrcodegen::QrCode::Ecc ecc);
+
+ /** Writes a QrToPng object to a png file at @_fileName.
+ * @return true if file could be written, false if file could not be written */
+ bool writeToPNG();
+
+private:
+ std::string _fileName;
+ int _size;
+ int _minModulePixelSize;
+ std::string _text;
+ bool _overwriteExistingFile;
+ qrcodegen::QrCode::Ecc _ecc;
+
+ /** Writes the PNG file. Constructs a vector with
+ * each element being a row of RGB 8.8.8 pixels, the
+ * format is geared towards the tinypngoutput library.
+ * @param qrData the code returned by the qrcodegen library
+ * @return true if file could be written, false if file could not be written */
+ [[nodiscard]] bool _writeToPNG(const qrcodegen::QrCode &qrData) const;
+
+ /* returns the width/height of the image based on the max image size
+ * and qr width. Ex. If the max img size is 90, the qr code size 29
+ * the qr module pixel size will be 3, the image size will be 3*29=87. */
+ [[nodiscard]] uint32_t _imgSize(const qrcodegen::QrCode &qrData) const;
+
+ [[nodiscard]] uint32_t _imgSizeWithBorder(const qrcodegen::QrCode &qrData) const;
+};
+
+#endif //QR_TO_PNG_H
\ No newline at end of file
diff --git a/QRCode/qrcode.cpp b/QRCode/qrcode.cpp
new file mode 100644
index 0000000..4d5b93f
--- /dev/null
+++ b/QRCode/qrcode.cpp
@@ -0,0 +1,831 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * Copyright (c) Project Nayuki. (MIT License)
+ * https://www.nayuki.io/page/qr-code-generator-library
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising from,
+ * out of or in connection with the Software or the use or other dealings in the
+ * Software.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "qrcode.hpp"
+#include
+
+using std::int8_t;
+using std::uint8_t;
+using std::size_t;
+using std::vector;
+
+
+namespace qrcodegen {
+
+/*---- Class QrSegment ----*/
+
+QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
+ modeBits(mode) {
+ numBitsCharCount[0] = cc0;
+ numBitsCharCount[1] = cc1;
+ numBitsCharCount[2] = cc2;
+}
+
+
+int QrSegment::Mode::getModeBits() const {
+ return modeBits;
+}
+
+
+int QrSegment::Mode::numCharCountBits(int ver) const {
+ return numBitsCharCount[(ver + 7) / 17];
+}
+
+
+const QrSegment::Mode QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
+const QrSegment::Mode QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
+const QrSegment::Mode QrSegment::Mode::BYTE (0x4, 8, 16, 16);
+const QrSegment::Mode QrSegment::Mode::KANJI (0x8, 8, 10, 12);
+const QrSegment::Mode QrSegment::Mode::ECI (0x7, 0, 0, 0);
+
+
+QrSegment QrSegment::makeBytes(const vector &data) {
+ if (data.size() > static_cast(INT_MAX))
+ throw std::length_error("Data too long");
+ BitBuffer bb;
+ for (uint8_t b : data)
+ bb.appendBits(b, 8);
+ return QrSegment(Mode::BYTE, static_cast(data.size()), std::move(bb));
+}
+
+
+QrSegment QrSegment::makeNumeric(const char *digits) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *digits != '\0'; digits++, charCount++) {
+ char c = *digits;
+ if (c < '0' || c > '9')
+ throw std::domain_error("String contains non-numeric characters");
+ accumData = accumData * 10 + (c - '0');
+ accumCount++;
+ if (accumCount == 3) {
+ bb.appendBits(static_cast(accumData), 10);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 or 2 digits remaining
+ bb.appendBits(static_cast(accumData), accumCount * 3 + 1);
+ return QrSegment(Mode::NUMERIC, charCount, std::move(bb));
+}
+
+
+QrSegment QrSegment::makeAlphanumeric(const char *text) {
+ BitBuffer bb;
+ int accumData = 0;
+ int accumCount = 0;
+ int charCount = 0;
+ for (; *text != '\0'; text++, charCount++) {
+ const char *temp = std::strchr(ALPHANUMERIC_CHARSET, *text);
+ if (temp == nullptr)
+ throw std::domain_error("String contains unencodable characters in alphanumeric mode");
+ accumData = accumData * 45 + static_cast(temp - ALPHANUMERIC_CHARSET);
+ accumCount++;
+ if (accumCount == 2) {
+ bb.appendBits(static_cast(accumData), 11);
+ accumData = 0;
+ accumCount = 0;
+ }
+ }
+ if (accumCount > 0) // 1 character remaining
+ bb.appendBits(static_cast(accumData), 6);
+ return QrSegment(Mode::ALPHANUMERIC, charCount, std::move(bb));
+}
+
+
+vector QrSegment::makeSegments(const char *text) {
+ // Select the most efficient segment encoding automatically
+ vector result;
+ if (*text == '\0'); // Leave result empty
+ else if (isNumeric(text))
+ result.push_back(makeNumeric(text));
+ else if (isAlphanumeric(text))
+ result.push_back(makeAlphanumeric(text));
+ else {
+ vector bytes;
+ for (; *text != '\0'; text++)
+ bytes.push_back(static_cast(*text));
+ result.push_back(makeBytes(bytes));
+ }
+ return result;
+}
+
+
+QrSegment QrSegment::makeEci(long assignVal) {
+ BitBuffer bb;
+ if (assignVal < 0)
+ throw std::domain_error("ECI assignment value out of range");
+ else if (assignVal < (1 << 7))
+ bb.appendBits(static_cast(assignVal), 8);
+ else if (assignVal < (1 << 14)) {
+ bb.appendBits(2, 2);
+ bb.appendBits(static_cast(assignVal), 14);
+ } else if (assignVal < 1000000L) {
+ bb.appendBits(6, 3);
+ bb.appendBits(static_cast(assignVal), 21);
+ } else
+ throw std::domain_error("ECI assignment value out of range");
+ return QrSegment(Mode::ECI, 0, std::move(bb));
+}
+
+
+QrSegment::QrSegment(const Mode &md, int numCh, const std::vector &dt) :
+ mode(&md),
+ numChars(numCh),
+ data(dt) {
+ if (numCh < 0)
+ throw std::domain_error("Invalid value");
+}
+
+
+QrSegment::QrSegment(const Mode &md, int numCh, std::vector &&dt) :
+ mode(&md),
+ numChars(numCh),
+ data(std::move(dt)) {
+ if (numCh < 0)
+ throw std::domain_error("Invalid value");
+}
+
+
+int QrSegment::getTotalBits(const vector &segs, int version) {
+ int result = 0;
+ for (const QrSegment &seg : segs) {
+ int ccbits = seg.mode->numCharCountBits(version);
+ if (seg.numChars >= (1L << ccbits))
+ return -1; // The segment's length doesn't fit the field's bit width
+ if (4 + ccbits > INT_MAX - result)
+ return -1; // The sum will overflow an int type
+ result += 4 + ccbits;
+ if (seg.data.size() > static_cast(INT_MAX - result))
+ return -1; // The sum will overflow an int type
+ result += static_cast(seg.data.size());
+ }
+ return result;
+}
+
+
+bool QrSegment::isNumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ char c = *text;
+ if (c < '0' || c > '9')
+ return false;
+ }
+ return true;
+}
+
+
+bool QrSegment::isAlphanumeric(const char *text) {
+ for (; *text != '\0'; text++) {
+ if (std::strchr(ALPHANUMERIC_CHARSET, *text) == nullptr)
+ return false;
+ }
+ return true;
+}
+
+
+const QrSegment::Mode &QrSegment::getMode() const {
+ return *mode;
+}
+
+
+int QrSegment::getNumChars() const {
+ return numChars;
+}
+
+
+const std::vector &QrSegment::getData() const {
+ return data;
+}
+
+
+const char *QrSegment::ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
+
+
+
+/*---- Class QrCode ----*/
+
+int QrCode::getFormatBits(Ecc ecl) {
+ switch (ecl) {
+ case Ecc::LOW : return 1;
+ case Ecc::MEDIUM : return 0;
+ case Ecc::QUARTILE: return 3;
+ case Ecc::HIGH : return 2;
+ default: throw std::logic_error("Unreachable");
+ }
+}
+
+
+QrCode QrCode::encodeText(const char *text, Ecc ecl) {
+ vector segs = QrSegment::makeSegments(text);
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeBinary(const vector &data, Ecc ecl) {
+ vector segs{QrSegment::makeBytes(data)};
+ return encodeSegments(segs, ecl);
+}
+
+
+QrCode QrCode::encodeSegments(const vector &segs, Ecc ecl,
+ int minVersion, int maxVersion, int mask, bool boostEcl) {
+ if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
+ throw std::invalid_argument("Invalid value");
+
+ // Find the minimal version number to use
+ int version, dataUsedBits;
+ for (version = minVersion; ; version++) {
+ int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
+ dataUsedBits = QrSegment::getTotalBits(segs, version);
+ if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
+ break; // This version number is found to be suitable
+ if (version >= maxVersion) { // All versions in the range could not fit the given data
+ std::ostringstream sb;
+ if (dataUsedBits == -1)
+ sb << "Segment too long";
+ else {
+ sb << "Data length = " << dataUsedBits << " bits, ";
+ sb << "Max capacity = " << dataCapacityBits << " bits";
+ }
+ throw data_too_long(sb.str());
+ }
+ }
+ assert(dataUsedBits != -1);
+
+ // Increase the error correction level while the data still fits in the current version number
+ for (Ecc newEcl : {Ecc::MEDIUM, Ecc::QUARTILE, Ecc::HIGH}) { // From low to high
+ if (boostEcl && dataUsedBits <= getNumDataCodewords(version, newEcl) * 8)
+ ecl = newEcl;
+ }
+
+ // Concatenate all segments to create the data bit string
+ BitBuffer bb;
+ for (const QrSegment &seg : segs) {
+ bb.appendBits(static_cast(seg.getMode().getModeBits()), 4);
+ bb.appendBits(static_cast(seg.getNumChars()), seg.getMode().numCharCountBits(version));
+ bb.insert(bb.end(), seg.getData().begin(), seg.getData().end());
+ }
+ assert(bb.size() == static_cast(dataUsedBits));
+
+ // Add terminator and pad up to a byte if applicable
+ size_t dataCapacityBits = static_cast(getNumDataCodewords(version, ecl)) * 8;
+ assert(bb.size() <= dataCapacityBits);
+ bb.appendBits(0, std::min(4, static_cast(dataCapacityBits - bb.size())));
+ bb.appendBits(0, (8 - static_cast(bb.size() % 8)) % 8);
+ assert(bb.size() % 8 == 0);
+
+ // Pad with alternating bytes until data capacity is reached
+ for (uint8_t padByte = 0xEC; bb.size() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
+ bb.appendBits(padByte, 8);
+
+ // Pack bits into bytes in big endian
+ vector dataCodewords(bb.size() / 8);
+ for (size_t i = 0; i < bb.size(); i++)
+ dataCodewords.at(i >> 3) |= (bb.at(i) ? 1 : 0) << (7 - (i & 7));
+
+ // Create the QR Code object
+ return QrCode(version, ecl, dataCodewords, mask);
+}
+
+
+QrCode::QrCode(int ver, Ecc ecl, const vector &dataCodewords, int msk) :
+ // Initialize fields and check arguments
+ version(ver),
+ errorCorrectionLevel(ecl) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw std::domain_error("Version value out of range");
+ if (msk < -1 || msk > 7)
+ throw std::domain_error("Mask value out of range");
+ size = ver * 4 + 17;
+ size_t sz = static_cast(size);
+ modules = vector >(sz, vector(sz)); // Initially all light
+ isFunction = vector >(sz, vector(sz));
+
+ // Compute ECC, draw modules
+ drawFunctionPatterns();
+ const vector allCodewords = addEccAndInterleave(dataCodewords);
+ drawCodewords(allCodewords);
+
+ // Do masking
+ if (msk == -1) { // Automatically choose best mask
+ long minPenalty = LONG_MAX;
+ for (int i = 0; i < 8; i++) {
+ applyMask(i);
+ drawFormatBits(i);
+ long penalty = getPenaltyScore();
+ if (penalty < minPenalty) {
+ msk = i;
+ minPenalty = penalty;
+ }
+ applyMask(i); // Undoes the mask due to XOR
+ }
+ }
+ assert(0 <= msk && msk <= 7);
+ mask = msk;
+ applyMask(msk); // Apply the final choice of mask
+ drawFormatBits(msk); // Overwrite old format bits
+
+ isFunction.clear();
+ isFunction.shrink_to_fit();
+}
+
+
+int QrCode::getVersion() const {
+ return version;
+}
+
+
+int QrCode::getSize() const {
+ return size;
+}
+
+
+QrCode::Ecc QrCode::getErrorCorrectionLevel() const {
+ return errorCorrectionLevel;
+}
+
+
+int QrCode::getMask() const {
+ return mask;
+}
+
+
+bool QrCode::getModule(int x, int y) const {
+ return 0 <= x && x < size && 0 <= y && y < size && module(x, y);
+}
+
+
+void QrCode::drawFunctionPatterns() {
+ // Draw horizontal and vertical timing patterns
+ for (int i = 0; i < size; i++) {
+ setFunctionModule(6, i, i % 2 == 0);
+ setFunctionModule(i, 6, i % 2 == 0);
+ }
+
+ // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
+ drawFinderPattern(3, 3);
+ drawFinderPattern(size - 4, 3);
+ drawFinderPattern(3, size - 4);
+
+ // Draw numerous alignment patterns
+ const vector alignPatPos = getAlignmentPatternPositions();
+ size_t numAlign = alignPatPos.size();
+ for (size_t i = 0; i < numAlign; i++) {
+ for (size_t j = 0; j < numAlign; j++) {
+ // Don't draw on the three finder corners
+ if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
+ drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
+ }
+ }
+
+ // Draw configuration data
+ drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
+ drawVersion();
+}
+
+
+void QrCode::drawFormatBits(int msk) {
+ // Calculate error correction code and pack bits
+ int data = getFormatBits(errorCorrectionLevel) << 3 | msk; // errCorrLvl is uint2, msk is uint3
+ int rem = data;
+ for (int i = 0; i < 10; i++)
+ rem = (rem << 1) ^ ((rem >> 9) * 0x537);
+ int bits = (data << 10 | rem) ^ 0x5412; // uint15
+ assert(bits >> 15 == 0);
+
+ // Draw first copy
+ for (int i = 0; i <= 5; i++)
+ setFunctionModule(8, i, getBit(bits, i));
+ setFunctionModule(8, 7, getBit(bits, 6));
+ setFunctionModule(8, 8, getBit(bits, 7));
+ setFunctionModule(7, 8, getBit(bits, 8));
+ for (int i = 9; i < 15; i++)
+ setFunctionModule(14 - i, 8, getBit(bits, i));
+
+ // Draw second copy
+ for (int i = 0; i < 8; i++)
+ setFunctionModule(size - 1 - i, 8, getBit(bits, i));
+ for (int i = 8; i < 15; i++)
+ setFunctionModule(8, size - 15 + i, getBit(bits, i));
+ setFunctionModule(8, size - 8, true); // Always dark
+}
+
+
+void QrCode::drawVersion() {
+ if (version < 7)
+ return;
+
+ // Calculate error correction code and pack bits
+ int rem = version; // version is uint6, in the range [7, 40]
+ for (int i = 0; i < 12; i++)
+ rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
+ long bits = static_cast(version) << 12 | rem; // uint18
+ assert(bits >> 18 == 0);
+
+ // Draw two copies
+ for (int i = 0; i < 18; i++) {
+ bool bit = getBit(bits, i);
+ int a = size - 11 + i % 3;
+ int b = i / 3;
+ setFunctionModule(a, b, bit);
+ setFunctionModule(b, a, bit);
+ }
+}
+
+
+void QrCode::drawFinderPattern(int x, int y) {
+ for (int dy = -4; dy <= 4; dy++) {
+ for (int dx = -4; dx <= 4; dx++) {
+ int dist = std::max(std::abs(dx), std::abs(dy)); // Chebyshev/infinity norm
+ int xx = x + dx, yy = y + dy;
+ if (0 <= xx && xx < size && 0 <= yy && yy < size)
+ setFunctionModule(xx, yy, dist != 2 && dist != 4);
+ }
+ }
+}
+
+
+void QrCode::drawAlignmentPattern(int x, int y) {
+ for (int dy = -2; dy <= 2; dy++) {
+ for (int dx = -2; dx <= 2; dx++)
+ setFunctionModule(x + dx, y + dy, std::max(std::abs(dx), std::abs(dy)) != 1);
+ }
+}
+
+
+void QrCode::setFunctionModule(int x, int y, bool isDark) {
+ size_t ux = static_cast(x);
+ size_t uy = static_cast(y);
+ modules .at(uy).at(ux) = isDark;
+ isFunction.at(uy).at(ux) = true;
+}
+
+
+bool QrCode::module(int x, int y) const {
+ return modules.at(static_cast(y)).at(static_cast(x));
+}
+
+
+vector QrCode::addEccAndInterleave(const vector &data) const {
+ if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel)))
+ throw std::invalid_argument("Invalid argument");
+
+ // Calculate parameter numbers
+ int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[static_cast(errorCorrectionLevel)][version];
+ int blockEccLen = ECC_CODEWORDS_PER_BLOCK [static_cast(errorCorrectionLevel)][version];
+ int rawCodewords = getNumRawDataModules(version) / 8;
+ int numShortBlocks = numBlocks - rawCodewords % numBlocks;
+ int shortBlockLen = rawCodewords / numBlocks;
+
+ // Split data into blocks and append ECC to each block
+ vector > blocks;
+ const vector rsDiv = reedSolomonComputeDivisor(blockEccLen);
+ for (int i = 0, k = 0; i < numBlocks; i++) {
+ vector dat(data.cbegin() + k, data.cbegin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
+ k += static_cast(dat.size());
+ const vector ecc = reedSolomonComputeRemainder(dat, rsDiv);
+ if (i < numShortBlocks)
+ dat.push_back(0);
+ dat.insert(dat.end(), ecc.cbegin(), ecc.cend());
+ blocks.push_back(std::move(dat));
+ }
+
+ // Interleave (not concatenate) the bytes from every block into a single sequence
+ vector result;
+ for (size_t i = 0; i < blocks.at(0).size(); i++) {
+ for (size_t j = 0; j < blocks.size(); j++) {
+ // Skip the padding byte in short blocks
+ if (i != static_cast(shortBlockLen - blockEccLen) || j >= static_cast(numShortBlocks))
+ result.push_back(blocks.at(j).at(i));
+ }
+ }
+ assert(result.size() == static_cast(rawCodewords));
+ return result;
+}
+
+
+void QrCode::drawCodewords(const vector &data) {
+ if (data.size() != static_cast(getNumRawDataModules(version) / 8))
+ throw std::invalid_argument("Invalid argument");
+
+ size_t i = 0; // Bit index into the data
+ // Do the funny zigzag scan
+ for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
+ if (right == 6)
+ right = 5;
+ for (int vert = 0; vert < size; vert++) { // Vertical counter
+ for (int j = 0; j < 2; j++) {
+ size_t x = static_cast(right - j); // Actual x coordinate
+ bool upward = ((right + 1) & 2) == 0;
+ size_t y = static_cast(upward ? size - 1 - vert : vert); // Actual y coordinate
+ if (!isFunction.at(y).at(x) && i < data.size() * 8) {
+ modules.at(y).at(x) = getBit(data.at(i >> 3), 7 - static_cast(i & 7));
+ i++;
+ }
+ // If this QR Code has any remainder bits (0 to 7), they were assigned as
+ // 0/false/light by the constructor and are left unchanged by this method
+ }
+ }
+ }
+ assert(i == data.size() * 8);
+}
+
+
+void QrCode::applyMask(int msk) {
+ if (msk < 0 || msk > 7)
+ throw std::domain_error("Mask value out of range");
+ size_t sz = static_cast(size);
+ for (size_t y = 0; y < sz; y++) {
+ for (size_t x = 0; x < sz; x++) {
+ bool invert;
+ switch (msk) {
+ case 0: invert = (x + y) % 2 == 0; break;
+ case 1: invert = y % 2 == 0; break;
+ case 2: invert = x % 3 == 0; break;
+ case 3: invert = (x + y) % 3 == 0; break;
+ case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
+ case 5: invert = x * y % 2 + x * y % 3 == 0; break;
+ case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
+ case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
+ default: throw std::logic_error("Unreachable");
+ }
+ modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
+ }
+ }
+}
+
+
+long QrCode::getPenaltyScore() const {
+ long result = 0;
+
+ // Adjacent modules in row having same color, and finder-like patterns
+ for (int y = 0; y < size; y++) {
+ bool runColor = false;
+ int runX = 0;
+ std::array runHistory = {};
+ for (int x = 0; x < size; x++) {
+ if (module(x, y) == runColor) {
+ runX++;
+ if (runX == 5)
+ result += PENALTY_N1;
+ else if (runX > 5)
+ result++;
+ } else {
+ finderPenaltyAddHistory(runX, runHistory);
+ if (!runColor)
+ result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
+ runColor = module(x, y);
+ runX = 1;
+ }
+ }
+ result += finderPenaltyTerminateAndCount(runColor, runX, runHistory) * PENALTY_N3;
+ }
+ // Adjacent modules in column having same color, and finder-like patterns
+ for (int x = 0; x < size; x++) {
+ bool runColor = false;
+ int runY = 0;
+ std::array runHistory = {};
+ for (int y = 0; y < size; y++) {
+ if (module(x, y) == runColor) {
+ runY++;
+ if (runY == 5)
+ result += PENALTY_N1;
+ else if (runY > 5)
+ result++;
+ } else {
+ finderPenaltyAddHistory(runY, runHistory);
+ if (!runColor)
+ result += finderPenaltyCountPatterns(runHistory) * PENALTY_N3;
+ runColor = module(x, y);
+ runY = 1;
+ }
+ }
+ result += finderPenaltyTerminateAndCount(runColor, runY, runHistory) * PENALTY_N3;
+ }
+
+ // 2*2 blocks of modules having same color
+ for (int y = 0; y < size - 1; y++) {
+ for (int x = 0; x < size - 1; x++) {
+ bool color = module(x, y);
+ if ( color == module(x + 1, y) &&
+ color == module(x, y + 1) &&
+ color == module(x + 1, y + 1))
+ result += PENALTY_N2;
+ }
+ }
+
+ // Balance of dark and light modules
+ int dark = 0;
+ for (const vector &row : modules) {
+ for (bool color : row) {
+ if (color)
+ dark++;
+ }
+ }
+ int total = size * size; // Note that size is odd, so dark/total != 1/2
+ // Compute the smallest integer k >= 0 such that (45-5k)% <= dark/total <= (55+5k)%
+ int k = static_cast((std::abs(dark * 20L - total * 10L) + total - 1) / total) - 1;
+ assert(0 <= k && k <= 9);
+ result += k * PENALTY_N4;
+ assert(0 <= result && result <= 2568888L); // Non-tight upper bound based on default values of PENALTY_N1, ..., N4
+ return result;
+}
+
+
+vector QrCode::getAlignmentPatternPositions() const {
+ if (version == 1)
+ return vector();
+ else {
+ int numAlign = version / 7 + 2;
+ int step = (version == 32) ? 26 :
+ (version * 4 + numAlign * 2 + 1) / (numAlign * 2 - 2) * 2;
+ vector result;
+ for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
+ result.insert(result.begin(), pos);
+ result.insert(result.begin(), 6);
+ return result;
+ }
+}
+
+
+int QrCode::getNumRawDataModules(int ver) {
+ if (ver < MIN_VERSION || ver > MAX_VERSION)
+ throw std::domain_error("Version number out of range");
+ int result = (16 * ver + 128) * ver + 64;
+ if (ver >= 2) {
+ int numAlign = ver / 7 + 2;
+ result -= (25 * numAlign - 10) * numAlign - 55;
+ if (ver >= 7)
+ result -= 36;
+ }
+ assert(208 <= result && result <= 29648);
+ return result;
+}
+
+
+int QrCode::getNumDataCodewords(int ver, Ecc ecl) {
+ return getNumRawDataModules(ver) / 8
+ - ECC_CODEWORDS_PER_BLOCK [static_cast(ecl)][ver]
+ * NUM_ERROR_CORRECTION_BLOCKS[static_cast(ecl)][ver];
+}
+
+
+vector QrCode::reedSolomonComputeDivisor(int degree) {
+ if (degree < 1 || degree > 255)
+ throw std::domain_error("Degree out of range");
+ // Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
+ // For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
+ vector result(static_cast(degree));
+ result.at(result.size() - 1) = 1; // Start off with the monomial x^0
+
+ // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
+ // and drop the highest monomial term which is always 1x^degree.
+ // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
+ uint8_t root = 1;
+ for (int i = 0; i < degree; i++) {
+ // Multiply the current product by (x - r^i)
+ for (size_t j = 0; j < result.size(); j++) {
+ result.at(j) = reedSolomonMultiply(result.at(j), root);
+ if (j + 1 < result.size())
+ result.at(j) ^= result.at(j + 1);
+ }
+ root = reedSolomonMultiply(root, 0x02);
+ }
+ return result;
+}
+
+
+vector QrCode::reedSolomonComputeRemainder(const vector &data, const vector &divisor) {
+ vector result(divisor.size());
+ for (uint8_t b : data) { // Polynomial division
+ uint8_t factor = b ^ result.at(0);
+ result.erase(result.begin());
+ result.push_back(0);
+ for (size_t i = 0; i < result.size(); i++)
+ result.at(i) ^= reedSolomonMultiply(divisor.at(i), factor);
+ }
+ return result;
+}
+
+
+uint8_t QrCode::reedSolomonMultiply(uint8_t x, uint8_t y) {
+ // Russian peasant multiplication
+ int z = 0;
+ for (int i = 7; i >= 0; i--) {
+ z = (z << 1) ^ ((z >> 7) * 0x11D);
+ z ^= ((y >> i) & 1) * x;
+ }
+ assert(z >> 8 == 0);
+ return static_cast(z);
+}
+
+
+int QrCode::finderPenaltyCountPatterns(const std::array &runHistory) const {
+ int n = runHistory.at(1);
+ assert(n <= size * 3);
+ bool core = n > 0 && runHistory.at(2) == n && runHistory.at(3) == n * 3 && runHistory.at(4) == n && runHistory.at(5) == n;
+ return (core && runHistory.at(0) >= n * 4 && runHistory.at(6) >= n ? 1 : 0)
+ + (core && runHistory.at(6) >= n * 4 && runHistory.at(0) >= n ? 1 : 0);
+}
+
+
+int QrCode::finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array &runHistory) const {
+ if (currentRunColor) { // Terminate dark run
+ finderPenaltyAddHistory(currentRunLength, runHistory);
+ currentRunLength = 0;
+ }
+ currentRunLength += size; // Add light border to final run
+ finderPenaltyAddHistory(currentRunLength, runHistory);
+ return finderPenaltyCountPatterns(runHistory);
+}
+
+
+void QrCode::finderPenaltyAddHistory(int currentRunLength, std::array &runHistory) const {
+ if (runHistory.at(0) == 0)
+ currentRunLength += size; // Add light border to initial run
+ std::copy_backward(runHistory.cbegin(), runHistory.cend() - 1, runHistory.end());
+ runHistory.at(0) = currentRunLength;
+}
+
+
+bool QrCode::getBit(long x, int i) {
+ return ((x >> i) & 1) != 0;
+}
+
+
+/*---- Tables of constants ----*/
+
+const int QrCode::PENALTY_N1 = 3;
+const int QrCode::PENALTY_N2 = 3;
+const int QrCode::PENALTY_N3 = 40;
+const int QrCode::PENALTY_N4 = 10;
+
+
+const int8_t QrCode::ECC_CODEWORDS_PER_BLOCK[4][41] = {
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Low
+ {-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28}, // Medium
+ {-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // Quartile
+ {-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30}, // High
+};
+
+const int8_t QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
+ // Version: (note that index 0 is for padding, and is set to an illegal value)
+ //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
+ {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
+ {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
+ {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
+ {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
+};
+
+
+data_too_long::data_too_long(const std::string &msg) :
+ std::length_error(msg) {}
+
+
+
+/*---- Class BitBuffer ----*/
+
+BitBuffer::BitBuffer()
+ : std::vector() {}
+
+
+void BitBuffer::appendBits(std::uint32_t val, int len) {
+ if (len < 0 || len > 31 || val >> len != 0)
+ throw std::domain_error("Value out of range");
+ for (int i = len - 1; i >= 0; i--) // Append bit by bit
+ this->push_back(((val >> i) & 1) != 0);
+}
+
+}
diff --git a/QRCode/qrcode.hpp b/QRCode/qrcode.hpp
new file mode 100644
index 0000000..1355156
--- /dev/null
+++ b/QRCode/qrcode.hpp
@@ -0,0 +1,549 @@
+/*
+ * QR Code generator library (C++)
+ *
+ * Copyright (c) Project Nayuki. (MIT License)
+ * https://www.nayuki.io/page/qr-code-generator-library
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+ * the Software, and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ * - The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ * - The Software is provided "as is", without warranty of any kind, express or
+ * implied, including but not limited to the warranties of merchantability,
+ * fitness for a particular purpose and noninfringement. In no event shall the
+ * authors or copyright holders be liable for any claim, damages or other
+ * liability, whether in an action of contract, tort or otherwise, arising from,
+ * out of or in connection with the Software or the use or other dealings in the
+ * Software.
+ */
+
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+
+
+namespace qrcodegen {
+
+ /*
+ * A segment of character/binary/control data in a QR Code symbol.
+ * Instances of this class are immutable.
+ * The mid-level way to create a segment is to take the payload data
+ * and call a static factory function such as QrSegment::makeNumeric().
+ * The low-level way to create a segment is to custom-make the bit buffer
+ * and call the QrSegment() constructor with appropriate values.
+ * This segment class imposes no length restrictions, but QR Codes have restrictions.
+ * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
+ * Any segment longer than this is meaningless for the purpose of generating QR Codes.
+ */
+ class QrSegment final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * Describes how a segment's data bits are interpreted. Immutable.
+ */
+ public: class Mode final {
+
+ /*-- Constants --*/
+
+ public: static const Mode NUMERIC;
+ public: static const Mode ALPHANUMERIC;
+ public: static const Mode BYTE;
+ public: static const Mode KANJI;
+ public: static const Mode ECI;
+
+
+ /*-- Fields --*/
+
+ // The mode indicator bits, which is a uint4 value (range 0 to 15).
+ private: int modeBits;
+
+ // Number of character count bits for three different version ranges.
+ private: int numBitsCharCount[3];
+
+
+ /*-- Constructor --*/
+
+ private: Mode(int mode, int cc0, int cc1, int cc2);
+
+
+ /*-- Methods --*/
+
+ /*
+ * (Package-private) Returns the mode indicator bits, which is an unsigned 4-bit value (range 0 to 15).
+ */
+ public: int getModeBits() const;
+
+ /*
+ * (Package-private) Returns the bit width of the character count field for a segment in
+ * this mode in a QR Code at the given version number. The result is in the range [0, 16].
+ */
+ public: int numCharCountBits(int ver) const;
+
+ };
+
+
+
+ /*---- Static factory functions (mid level) ----*/
+
+ /*
+ * Returns a segment representing the given binary data encoded in
+ * byte mode. All input byte vectors are acceptable. Any text string
+ * can be converted to UTF-8 bytes and encoded as a byte mode segment.
+ */
+ public: static QrSegment makeBytes(const std::vector& data);
+
+
+ /*
+ * Returns a segment representing the given string of decimal digits encoded in numeric mode.
+ */
+ public: static QrSegment makeNumeric(const char* digits);
+
+
+ /*
+ * Returns a segment representing the given text string encoded in alphanumeric mode.
+ * The characters allowed are: 0 to 9, A to Z (uppercase only), space,
+ * dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+ */
+ public: static QrSegment makeAlphanumeric(const char* text);
+
+
+ /*
+ * Returns a list of zero or more segments to represent the given text string. The result
+ * may use various segment modes and switch modes to optimize the length of the bit stream.
+ */
+ public: static std::vector makeSegments(const char* text);
+
+
+ /*
+ * Returns a segment representing an Extended Channel Interpretation
+ * (ECI) designator with the given assignment value.
+ */
+ public: static QrSegment makeEci(long assignVal);
+
+
+ /*---- Public static helper functions ----*/
+
+ /*
+ * Tests whether the given string can be encoded as a segment in numeric mode.
+ * A string is encodable iff each character is in the range 0 to 9.
+ */
+ public: static bool isNumeric(const char* text);
+
+
+ /*
+ * Tests whether the given string can be encoded as a segment in alphanumeric mode.
+ * A string is encodable iff each character is in the following set: 0 to 9, A to Z
+ * (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
+ */
+ public: static bool isAlphanumeric(const char* text);
+
+
+
+ /*---- Instance fields ----*/
+
+ /* The mode indicator of this segment. Accessed through getMode(). */
+ private: const Mode* mode;
+
+ /* The length of this segment's unencoded data. Measured in characters for
+ * numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
+ * Always zero or positive. Not the same as the data's bit length.
+ * Accessed through getNumChars(). */
+ private: int numChars;
+
+ /* The data bits of this segment. Accessed through getData(). */
+ private: std::vector data;
+
+
+ /*---- Constructors (low level) ----*/
+
+ /*
+ * Creates a new QR Code segment with the given attributes and data.
+ * The character count (numCh) must agree with the mode and the bit buffer length,
+ * but the constraint isn't checked. The given bit buffer is copied and stored.
+ */
+ public: QrSegment(const Mode& md, int numCh, const std::vector& dt);
+
+
+ /*
+ * Creates a new QR Code segment with the given parameters and data.
+ * The character count (numCh) must agree with the mode and the bit buffer length,
+ * but the constraint isn't checked. The given bit buffer is moved and stored.
+ */
+ public: QrSegment(const Mode& md, int numCh, std::vector&& dt);
+
+
+ /*---- Methods ----*/
+
+ /*
+ * Returns the mode field of this segment.
+ */
+ public: const Mode& getMode() const;
+
+
+ /*
+ * Returns the character count field of this segment.
+ */
+ public: int getNumChars() const;
+
+
+ /*
+ * Returns the data bits of this segment.
+ */
+ public: const std::vector& getData() const;
+
+
+ // (Package-private) Calculates the number of bits needed to encode the given segments at
+ // the given version. Returns a non-negative number if successful. Otherwise returns -1 if a
+ // segment has too many characters to fit its length field, or the total bits exceeds INT_MAX.
+ public: static int getTotalBits(const std::vector& segs, int version);
+
+
+ /*---- Private constant ----*/
+
+ /* The set of all legal characters in alphanumeric mode, where
+ * each character value maps to the index in the string. */
+ private: static const char* ALPHANUMERIC_CHARSET;
+
+ };
+
+
+
+ /*
+ * A QR Code symbol, which is a type of two-dimension barcode.
+ * Invented by Denso Wave and described in the ISO/IEC 18004 standard.
+ * Instances of this class represent an immutable square grid of dark and light cells.
+ * The class provides static factory functions to create a QR Code from text or binary data.
+ * The class covers the QR Code Model 2 specification, supporting all versions (sizes)
+ * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
+ *
+ * Ways to create a QR Code object:
+ * - High level: Take the payload data and call QrCode::encodeText() or QrCode::encodeBinary().
+ * - Mid level: Custom-make the list of segments and call QrCode::encodeSegments().
+ * - Low level: Custom-make the array of data codeword bytes (including
+ * segment headers and final padding, excluding error correction codewords),
+ * supply the appropriate version number, and call the QrCode() constructor.
+ * (Note that all ways require supplying the desired error correction level.)
+ */
+ class QrCode final {
+
+ /*---- Public helper enumeration ----*/
+
+ /*
+ * The error correction level in a QR Code symbol.
+ */
+ public: enum class Ecc {
+ LOW = 0, // The QR Code can tolerate about 7% erroneous codewords
+ MEDIUM, // The QR Code can tolerate about 15% erroneous codewords
+ QUARTILE, // The QR Code can tolerate about 25% erroneous codewords
+ HIGH, // The QR Code can tolerate about 30% erroneous codewords
+ };
+
+
+ // Returns a value in the range 0 to 3 (unsigned 2-bit integer).
+ private: static int getFormatBits(Ecc ecl);
+
+
+
+ /*---- Static factory functions (high level) ----*/
+
+ /*
+ * Returns a QR Code representing the given Unicode text string at the given error correction level.
+ * As a conservative upper bound, this function is guaranteed to succeed for strings that have 2953 or fewer
+ * UTF-8 code units (not Unicode code points) if the low error correction level is used. The smallest possible
+ * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than
+ * the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeText(const char* text, Ecc ecl);
+
+
+ /*
+ * Returns a QR Code representing the given binary data at the given error correction level.
+ * This function always encodes using the binary segment mode, not any text mode. The maximum number of
+ * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
+ * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
+ */
+ public: static QrCode encodeBinary(const std::vector& data, Ecc ecl);
+
+
+ /*---- Static factory functions (mid level) ----*/
+
+ /*
+ * Returns a QR Code representing the given segments with the given encoding parameters.
+ * The smallest possible QR Code version within the given range is automatically
+ * chosen for the output. Iff boostEcl is true, then the ECC level of the result
+ * may be higher than the ecl argument if it can be done without increasing the
+ * version. The mask number is either between 0 to 7 (inclusive) to force that
+ * mask, or -1 to automatically choose an appropriate mask (which may be slow).
+ * This function allows the user to create a custom sequence of segments that switches
+ * between modes (such as alphanumeric and byte) to encode text in less space.
+ * This is a mid-level API; the high-level API is encodeText() and encodeBinary().
+ */
+ public: static QrCode encodeSegments(const std::vector& segs, Ecc ecl,
+ int minVersion = 1, int maxVersion = 40, int mask = -1, bool boostEcl = true); // All optional parameters
+
+
+
+ /*---- Instance fields ----*/
+
+ // Immutable scalar parameters:
+
+ /* The version number of this QR Code, which is between 1 and 40 (inclusive).
+ * This determines the size of this barcode. */
+ private: int version;
+
+ /* The width and height of this QR Code, measured in modules, between
+ * 21 and 177 (inclusive). This is equal to version * 4 + 17. */
+ private: int size;
+
+ /* The error correction level used in this QR Code. */
+ private: Ecc errorCorrectionLevel;
+
+ /* The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
+ * Even if a QR Code is created with automatic masking requested (mask = -1),
+ * the resulting object still has a mask value between 0 and 7. */
+ private: int mask;
+
+ // Private grids of modules/pixels, with dimensions of size*size:
+
+ // The modules of this QR Code (false = light, true = dark).
+ // Immutable after constructor finishes. Accessed through getModule().
+ private: std::vector > modules;
+
+ // Indicates function modules that are not subjected to masking. Discarded when constructor finishes.
+ private: std::vector > isFunction;
+
+
+
+ /*---- Constructor (low level) ----*/
+
+ /*
+ * Creates a new QR Code with the given version number,
+ * error correction level, data codeword bytes, and mask number.
+ * This is a low-level API that most users should not use directly.
+ * A mid-level API is the encodeSegments() function.
+ */
+ public: QrCode(int ver, Ecc ecl, const std::vector& dataCodewords, int msk);
+
+
+
+ /*---- Public instance methods ----*/
+
+ /*
+ * Returns this QR Code's version, in the range [1, 40].
+ */
+ public: int getVersion() const;
+
+
+ /*
+ * Returns this QR Code's size, in the range [21, 177].
+ */
+ public: int getSize() const;
+
+
+ /*
+ * Returns this QR Code's error correction level.
+ */
+ public: Ecc getErrorCorrectionLevel() const;
+
+
+ /*
+ * Returns this QR Code's mask, in the range [0, 7].
+ */
+ public: int getMask() const;
+
+
+ /*
+ * Returns the color of the module (pixel) at the given coordinates, which is false
+ * for light or true for dark. The top left corner has the coordinates (x=0, y=0).
+ * If the given coordinates are out of bounds, then false (light) is returned.
+ */
+ public: bool getModule(int x, int y) const;
+
+
+
+ /*---- Private helper methods for constructor: Drawing function modules ----*/
+
+ // Reads this object's version field, and draws and marks all function modules.
+ private: void drawFunctionPatterns();
+
+
+ // Draws two copies of the format bits (with its own error correction code)
+ // based on the given mask and this object's error correction level field.
+ private: void drawFormatBits(int msk);
+
+
+ // Draws two copies of the version bits (with its own error correction code),
+ // based on this object's version field, iff 7 <= version <= 40.
+ private: void drawVersion();
+
+
+ // Draws a 9*9 finder pattern including the border separator,
+ // with the center module at (x, y). Modules can be out of bounds.
+ private: void drawFinderPattern(int x, int y);
+
+
+ // Draws a 5*5 alignment pattern, with the center module
+ // at (x, y). All modules must be in bounds.
+ private: void drawAlignmentPattern(int x, int y);
+
+
+ // Sets the color of a module and marks it as a function module.
+ // Only used by the constructor. Coordinates must be in bounds.
+ private: void setFunctionModule(int x, int y, bool isDark);
+
+
+ // Returns the color of the module at the given coordinates, which must be in range.
+ private: bool module(int x, int y) const;
+
+
+ /*---- Private helper methods for constructor: Codewords and masking ----*/
+
+ // Returns a new byte string representing the given data with the appropriate error correction
+ // codewords appended to it, based on this object's version and error correction level.
+ private: std::vector addEccAndInterleave(const std::vector& data) const;
+
+
+ // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
+ // data area of this QR Code. Function modules need to be marked off before this is called.
+ private: void drawCodewords(const std::vector& data);
+
+
+ // XORs the codeword modules in this QR Code with the given mask pattern.
+ // The function modules must be marked and the codeword bits must be drawn
+ // before masking. Due to the arithmetic of XOR, calling applyMask() with
+ // the same mask value a second time will undo the mask. A final well-formed
+ // QR Code needs exactly one (not zero, two, etc.) mask applied.
+ private: void applyMask(int msk);
+
+
+ // Calculates and returns the penalty score based on state of this QR Code's current modules.
+ // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
+ private: long getPenaltyScore() const;
+
+
+
+ /*---- Private helper functions ----*/
+
+ // Returns an ascending list of positions of alignment patterns for this version number.
+ // Each position is in the range [0,177), and are used on both the x and y axes.
+ // This could be implemented as lookup table of 40 variable-length lists of unsigned bytes.
+ private: std::vector getAlignmentPatternPositions() const;
+
+
+ // Returns the number of data bits that can be stored in a QR Code of the given version number, after
+ // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
+ // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
+ private: static int getNumRawDataModules(int ver);
+
+
+ // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
+ // QR Code of the given version number and error correction level, with remainder bits discarded.
+ // This stateless pure function could be implemented as a (40*4)-cell lookup table.
+ private: static int getNumDataCodewords(int ver, Ecc ecl);
+
+
+ // Returns a Reed-Solomon ECC generator polynomial for the given degree. This could be
+ // implemented as a lookup table over all possible parameter values, instead of as an algorithm.
+ private: static std::vector reedSolomonComputeDivisor(int degree);
+
+
+ // Returns the Reed-Solomon error correction codeword for the given data and divisor polynomials.
+ private: static std::vector reedSolomonComputeRemainder(const std::vector& data, const std::vector& divisor);
+
+
+ // Returns the product of the two given field elements modulo GF(2^8/0x11D).
+ // All inputs are valid. This could be implemented as a 256*256 lookup table.
+ private: static std::uint8_t reedSolomonMultiply(std::uint8_t x, std::uint8_t y);
+
+
+ // Can only be called immediately after a light run is added, and
+ // returns either 0, 1, or 2. A helper function for getPenaltyScore().
+ private: int finderPenaltyCountPatterns(const std::array& runHistory) const;
+
+
+ // Must be called at the end of a line (row or column) of modules. A helper function for getPenaltyScore().
+ private: int finderPenaltyTerminateAndCount(bool currentRunColor, int currentRunLength, std::array& runHistory) const;
+
+
+ // Pushes the given value to the front and drops the last value. A helper function for getPenaltyScore().
+ private: void finderPenaltyAddHistory(int currentRunLength, std::array& runHistory) const;
+
+
+ // Returns true iff the i'th bit of x is set to 1.
+ private: static bool getBit(long x, int i);
+
+
+ /*---- Constants and tables ----*/
+
+ // The minimum version number supported in the QR Code Model 2 standard.
+ public: static constexpr int MIN_VERSION = 1;
+
+ // The maximum version number supported in the QR Code Model 2 standard.
+ public: static constexpr int MAX_VERSION = 40;
+
+
+ // For use in getPenaltyScore(), when evaluating which mask is best.
+ private: static const int PENALTY_N1;
+ private: static const int PENALTY_N2;
+ private: static const int PENALTY_N3;
+ private: static const int PENALTY_N4;
+
+
+ private: static const std::int8_t ECC_CODEWORDS_PER_BLOCK[4][41];
+ private: static const std::int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
+
+ };
+
+
+
+ /*---- Public exception class ----*/
+
+ /*
+ * Thrown when the supplied data does not fit any QR Code version. Ways to handle this exception include:
+ * - Decrease the error correction level if it was greater than Ecc::LOW.
+ * - If the encodeSegments() function was called with a maxVersion argument, then increase
+ * it if it was less than QrCode::MAX_VERSION. (This advice does not apply to the other
+ * factory functions because they search all versions up to QrCode::MAX_VERSION.)
+ * - Split the text data into better or optimal segments in order to reduce the number of bits required.
+ * - Change the text or binary data to be shorter.
+ * - Change the text to fit the character set of a particular segment mode (e.g. alphanumeric).
+ * - Propagate the error upward to the caller/user.
+ */
+ class data_too_long : public std::length_error {
+
+ public: explicit data_too_long(const std::string& msg);
+
+ };
+
+
+
+ /*
+ * An appendable sequence of bits (0s and 1s). Mainly used by QrSegment.
+ */
+ class BitBuffer final : public std::vector {
+
+ /*---- Constructor ----*/
+
+ // Creates an empty bit buffer (length 0).
+ public: BitBuffer();
+
+
+
+ /*---- Method ----*/
+
+ // Appends the given number of low-order bits of the given value
+ // to this buffer. Requires 0 <= len <= 31 and val < 2^len.
+ public: void appendBits(std::uint32_t val, int len);
+
+ };
+
+}
diff --git a/README.md b/README.md
index a607349..56926db 100644
--- a/README.md
+++ b/README.md
@@ -3,16 +3,32 @@ KeyAuth C++ Library
This is the source code of the library_x64.lib file from https://github.com/KeyAuth/KeyAuth-CPP-Example
-**This is NOT open-source, in respect to copyright usage. Commercial use is prohibited, read below for further clarification**
-
-Mutli Support : x86/x64
+Multi Support : x86/x64
## **Bugs**
-If the default example not added to your software isn't functioning how it should, please report a bug here https://keyauth.cc/app/?page=forms
+If you are using our example with no significant changes, and you are having problems, please Report Bug here https://keyauth.cc/app/?page=forms
However, we do **NOT** provide support for adding KeyAuth to your project. If you can't figure this out you should use Google or YouTube to learn more about the programming language you want to sell a program in.
+## Different Architectures
+x86 :
+
+1- Compile libcurl can be downloaded from curl.se and compiled by x86 Native Tools (Visual Studio Tools)
+
+2- Lib Configuration -> General -> C++ Language Standard -> ISO C++17 Standard (/std:c++17)
+
+3- Lib Configuration -> Advanced -> Character Set -> Multi-Byte Character Set
+
+4- Lib Configuration -> Preprocessor definiton for CURL -> CURL_STATICLIB
+
+## **What is KeyAuth?**
+
+KeyAuth is an Open source authentication system with cloud hosting plans as well. Client SDKs available for [C#](https://github.com/KeyAuth/KeyAuth-CSHARP-Example), [C++](https://github.com/KeyAuth/KeyAuth-CPP-Example), [Python](https://github.com/KeyAuth/KeyAuth-Python-Example), [Java](https://github.com/KeyAuth-Archive/KeyAuth-JAVA-api), [JavaScript](https://github.com/mazkdevf/KeyAuth-JS-Example), [VB.NET](https://github.com/KeyAuth/KeyAuth-VB-Example), [PHP](https://github.com/KeyAuth/KeyAuth-PHP-Example), [Rust](https://github.com/KeyAuth/KeyAuth-Rust-Example), [Go](https://github.com/mazkdevf/KeyAuth-Go-Example), [Lua](https://github.com/mazkdevf/KeyAuth-Lua-Examples), [Ruby](https://github.com/mazkdevf/KeyAuth-Ruby-Example), and [Perl](https://github.com/mazkdevf/KeyAuth-Perl-Example). KeyAuth has several unique features such as memory streaming, webhook function where you can send requests to API without leaking the API, discord webhook notifications, ban the user securely through the application at your discretion. Feel free to join https://t.me/keyauth if you have questions or suggestions.
+
+> [!TIP]
+> https://vaultcord.com FREE Discord bot to Backup server, members, channels, messages & more. Custom verify page, block alt accounts, VPNs & more.
+
## Copyright License
KeyAuth is licensed under **Elastic License 2.0**
@@ -30,16 +46,3 @@ of the licensor in the software. Any use of the licensor’s trademarks is subje
to applicable law.
Thank you for your compliance, we work hard on the development of KeyAuth and do not appreciate our copyright being infringed.
-
-## Different Architectures
-x86 :
-
-1- Compile libcurl can be downloaded from curl.se and compiled by x86 Native Tools (Visual Studio Tools)
-
-2- Lib Configuration -> General -> C++ Language Standard -> ISO C++17 Standard (/std:c++17)
-
-3- Lib Configuration -> Advanced -> Character Set -> Multi-Byte Character Set
-
-4- Lib Configuration -> Preprocessor definiton for CURL -> CURL_STATICLIB
-
-Looking for a Discord bot made by the KeyAuth & RestoreCord founder that you can use to backup your Discord members, server settings, and messages? Go to https://vaultcord.com
diff --git a/Security.hpp b/Security.hpp
new file mode 100644
index 0000000..958c0d7
--- /dev/null
+++ b/Security.hpp
@@ -0,0 +1,106 @@
+#pragma once
+#include
+#include
+#include
+#include
+#include
+
+// code submitted in pull request from https://github.com/sbtoonz, authored by KeePassXC https://github.com/keepassxreboot/keepassxc/blob/dab7047113c4ad4ffead944d5c4ebfb648c1d0b0/src/core/Bootstrap.cpp#L121
+inline bool LockMemAccess()
+{
+ bool bSuccess = false;
+ // Process token and user
+ HANDLE hToken = nullptr;
+ PTOKEN_USER pTokenUser = nullptr;
+ DWORD cbBufferSize = 0;
+
+ // Access control list
+ PACL pACL = nullptr;
+ DWORD cbACL = 0;
+
+ // Open the access token associated with the calling process
+ if (!OpenProcessToken(
+ GetCurrentProcess(),
+ TOKEN_QUERY,
+ &hToken
+ )) {
+ goto Cleanup;
+ }
+
+ // Retrieve the token information in a TOKEN_USER structure
+ GetTokenInformation(
+ hToken,
+ TokenUser, // request for a TOKEN_USER structure
+ nullptr,
+ 0,
+ &cbBufferSize
+ );
+
+ pTokenUser = static_cast(malloc(cbBufferSize));
+ if (pTokenUser == nullptr) {
+ goto Cleanup;
+ }
+
+ if (!GetTokenInformation(
+ hToken,
+ TokenUser,
+ pTokenUser,
+ cbBufferSize,
+ &cbBufferSize
+ )) {
+ goto Cleanup;
+ }
+
+ if (!IsValidSid(pTokenUser->User.Sid)) {
+ goto Cleanup;
+ }
+
+ // Calculate the amount of memory that must be allocated for the DACL
+ cbACL = sizeof(ACL) + sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pTokenUser->User.Sid);
+
+ // Create and initialize an ACL
+ pACL = static_cast(malloc(cbACL));
+ if (pACL == nullptr) {
+ goto Cleanup;
+ }
+
+ if (!InitializeAcl(pACL, cbACL, ACL_REVISION)) {
+ goto Cleanup;
+ }
+
+ // Add allowed access control entries, everything else is denied
+ if (!AddAccessAllowedAce(
+ pACL,
+ ACL_REVISION,
+ SYNCHRONIZE | PROCESS_QUERY_LIMITED_INFORMATION | PROCESS_TERMINATE, // same as protected process
+ pTokenUser->User.Sid // pointer to the trustee's SID
+ )) {
+ goto Cleanup;
+ }
+
+ // Set discretionary access control list
+ bSuccess = ERROR_SUCCESS == SetSecurityInfo(
+ GetCurrentProcess(), // object handle
+ SE_KERNEL_OBJECT, // type of object
+ DACL_SECURITY_INFORMATION, // change only the objects DACL
+ nullptr, nullptr, // do not change owner or group
+ pACL, // DACL specified
+ nullptr // do not change SACL
+ );
+
+Cleanup:
+
+ if (pACL != nullptr) {
+ free(pACL);
+
+ }
+ if (pTokenUser != nullptr) {
+ free(pTokenUser);
+
+ }
+ if (hToken != nullptr) {
+ CloseHandle(hToken);
+
+ }
+ return bSuccess;
+}
\ No newline at end of file
diff --git a/auth.cpp b/auth.cpp
new file mode 100644
index 0000000..b199c8d
--- /dev/null
+++ b/auth.cpp
@@ -0,0 +1,2074 @@
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0600
+#endif
+
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN
+#endif
+
+#define _CRT_SECURE_NO_WARNINGS
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+
+#pragma comment(lib, "rpcrt4.lib")
+#pragma comment(lib, "httpapi.lib")
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#pragma comment( lib, "psapi.lib" )
+#include
+
+#include
+#include
+
+#include "Security.hpp"
+#include "killEmulator.hpp"
+#include
+#include
+#include
+
+#define SHA256_HASH_SIZE 32
+
+static std::string hexDecode(const std::string& hex);
+std::string get_str_between_two_str(const std::string& s, const std::string& start_delim, const std::string& stop_delim);
+int VerifyPayload(std::string signature, std::string timestamp, std::string body);
+void checkInit();
+std::string checksum();
+void debugInfo(std::string data, std::string url, std::string response, std::string headers);
+void modify();
+void runChecks();
+void checkAtoms();
+void checkFiles();
+void checkRegistry();
+void error(std::string message);
+std::string generate_random_number();
+std::string seed;
+std::string signature;
+std::string signatureTimestamp;
+bool initialized;
+std::string API_PUBLIC_KEY = "5586b4bc69c7a4b487e4563a4cd96afd39140f919bd31cea7d1c6a1e8439422b";
+
+void KeyAuth::api::init()
+{
+ CreateThread(0, 0, (LPTHREAD_START_ROUTINE)runChecks, 0, 0, 0);
+ std::string random_num = generate_random_number();
+ seed = random_num;
+ CreateThread(0, 0, (LPTHREAD_START_ROUTINE)modify, 0, 0, 0);
+
+ if (ownerid.length() != 10)
+ {
+ MessageBoxA(0, XorStr("Application Not Setup Correctly. Please Watch Video Linked in main.cpp").c_str(), NULL, MB_ICONERROR);
+ LI_FN(exit)(0);
+ }
+
+ std::string hash = checksum();
+ CURL* curl = curl_easy_init();
+ auto data =
+ XorStr("type=init") +
+ XorStr("&ver=") + version +
+ XorStr("&hash=") + hash +
+ XorStr("&name=") + curl_easy_escape(curl, name.c_str(), 0) +
+ XorStr("&ownerid=") + ownerid;
+
+ // to ensure people removed secret from main.cpp (some people will forget to)
+ if (path.find("https") != std::string::npos) {
+ MessageBoxA(0, XorStr("You forgot to remove \"secret\" from main.cpp. Copy details from ").c_str(), NULL, MB_ICONERROR);
+ LI_FN(exit)(0);
+ }
+
+ if (path != "" || !path.empty()) {
+
+ if (!std::filesystem::exists(path)) {
+ MessageBoxA(0, XorStr("File not found. Please make sure the file exists.").c_str(), NULL, MB_ICONERROR);
+ LI_FN(exit)(0);
+ }
+ //get the contents of the file
+ std::ifstream file(path);
+ std::string token;
+ std::string thash;
+ std::getline(file, token);
+
+ auto exec = [&](const char* cmd) -> std::string
+ {
+ uint16_t line = -1;
+ std::array buffer;
+ std::string result;
+ std::unique_ptr pipe(_popen(cmd, "r"), _pclose);
+ if (!pipe) {
+ throw std::runtime_error(XorStr("popen() failed!"));
+ }
+
+ while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
+ result = buffer.data();
+ }
+ return result;
+ };
+
+ thash = exec(("certutil -hashfile \"" + path + XorStr("\" MD5 | find /i /v \"md5\" | find /i /v \"certutil\"")).c_str());
+
+ data += XorStr("&token=").c_str() + token;
+ data += XorStr("&thash=").c_str() + path;
+ }
+ curl_easy_cleanup(curl);
+
+ auto response = req(data, url);
+
+ if (response == XorStr("KeyAuth_Invalid").c_str()) {
+ MessageBoxA(0, XorStr("Application not found. Please copy strings directly from dashboard.").c_str(), NULL, MB_ICONERROR);
+ LI_FN(exit)(0);
+ }
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ load_response_data(json);
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ if (json[(XorStr("success"))])
+ {
+ if (json[(XorStr("newSession"))]) {
+ Sleep(100);
+ }
+ sessionid = json[(XorStr("sessionid"))];
+ initialized = true;
+ load_app_data(json[(XorStr("appinfo"))]);
+ }
+ else if (json[(XorStr("message"))] == XorStr("invalidver"))
+ {
+ std::string dl = json[(XorStr("download"))];
+ if (dl == "")
+ {
+ MessageBoxA(0, XorStr("Version in the loader does match the one on the dashboard, and the download link on dashboard is blank.\n\nTo fix this, either fix the loader so it matches the version on the dashboard. Or if you intended for it to have different versions, update the download link on dashboard so it will auto-update correctly.").c_str(), NULL, MB_ICONERROR);
+ }
+ else
+ {
+ ShellExecuteA(0, XorStr("open").c_str(), dl.c_str(), 0, 0, SW_SHOWNORMAL);
+ }
+ LI_FN(exit)(0);
+ }
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+size_t write_callback(void* contents, size_t size, size_t nmemb, void* userp) {
+ ((std::string*)userp)->append((char*)contents, size * nmemb);
+ return size * nmemb;
+}
+
+// Callback function to handle headers
+size_t header_callback(char* buffer, size_t size, size_t nitems, void* userdata) {
+ size_t totalSize = size * nitems;
+
+ // Convert the header to a string for easier processing
+ std::string header(buffer, totalSize);
+
+ // Find the x-signature-ed25519 header
+ const std::string signatureHeaderName = "x-signature-ed25519: ";
+ if (header.find(signatureHeaderName) == 0) {
+ // Extract the header value
+ signature = header.substr(signatureHeaderName.length());
+
+ // Remove any trailing newline or carriage return characters
+ signature.erase(signature.find_last_not_of("\r\n") + 1);
+ }
+
+ // Find the x-signature-timestamp header
+ const std::string signatureTimeHeaderName = "x-signature-timestamp: ";
+ if (header.find(signatureTimeHeaderName) == 0) {
+ // Extract the header value
+ signatureTimestamp = header.substr(signatureTimeHeaderName.length());
+
+ // Remove any trailing newline or carriage return characters
+ signatureTimestamp.erase(signatureTimestamp.find_last_not_of("\r\n") + 1);
+ }
+
+ return totalSize;
+}
+
+void KeyAuth::api::login(std::string username, std::string password, std::string code)
+{
+ checkInit();
+
+ std::string hwid = utils::get_hwid();
+ auto data =
+ XorStr("type=login") +
+ XorStr("&username=") + username +
+ XorStr("&pass=") + password +
+ XorStr("&code=") + code +
+ XorStr("&hwid=") + hwid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ if (json[(XorStr("success"))])
+ load_user_data(json[(XorStr("info"))]);
+
+ if (api::response.message != XorStr("Initialized").c_str()) {
+ LI_FN(GlobalAddAtomA)(seed.c_str());
+
+ std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed;
+ std::ofstream file(file_path);
+ if (file.is_open()) {
+ file << seed;
+ file.close();
+ }
+
+ std::string regPath = XorStr("Software\\").c_str() + seed;
+ HKEY hKey;
+ LONG result = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
+ if (result == ERROR_SUCCESS) {
+ LI_FN(RegSetValueExA)(hKey, seed.c_str(), 0, REG_SZ, reinterpret_cast(seed.c_str()), seed.size() + 1);
+ LI_FN(RegCloseKey)(hKey);
+ }
+
+ LI_FN(GlobalAddAtomA)(ownerid.c_str());
+ }
+ else {
+ LI_FN(exit)(12);
+ }
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::chatget(std::string channel)
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=chatget") +
+ XorStr("&channel=") + channel +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ load_channel_data(json);
+}
+
+bool KeyAuth::api::chatsend(std::string message, std::string channel)
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=chatsend") +
+ XorStr("&message=") + message +
+ XorStr("&channel=") + channel +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ load_response_data(json);
+ return json[("success")];
+}
+
+void KeyAuth::api::changeUsername(std::string newusername)
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=changeUsername") +
+ XorStr("&newUsername=") + newusername +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+KeyAuth::api::Tfa& KeyAuth::api::enable2fa(std::string code)
+{
+ checkInit();
+
+ KeyAuth::api::activate = true;
+
+ auto data =
+ XorStr("type=2faenable") +
+ XorStr("&code=") + code +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+
+ if (json.contains("2fa")) {
+
+ api::response.success = json["success"];
+ api::tfa.secret = json["2fa"]["secret_code"];
+ api::tfa.link = json["2fa"]["QRCode"];
+ }
+ else {
+ load_response_data(json);
+ }
+
+ return api::tfa;
+}
+
+KeyAuth::api::Tfa& KeyAuth::api::disable2fa(std::string code)
+{
+ checkInit();
+
+ KeyAuth::api::activate = false;
+
+ if (code.empty()) {
+ return this->tfa.handleInput(*this);
+ }
+
+
+ auto data =
+ XorStr("type=2fadisable") +
+ XorStr("&code=") + code +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+
+ auto json = response_decoder.parse(response);
+
+ load_response_data(json);
+
+ return api::tfa;
+}
+
+void KeyAuth::api::Tfa::QrCode() {
+ auto qrcode = QrToPng("QRCode.png", 300, 3, KeyAuth::api::Tfa::link, true, qrcodegen::QrCode::Ecc::MEDIUM);
+ qrcode.writeToPNG();
+}
+
+KeyAuth::api::Tfa& KeyAuth::api::Tfa::handleInput(KeyAuth::api& instance) {
+
+ if (instance.activate) {
+ QrCode();
+
+ ShellExecuteA(0, XorStr("open").c_str(), XorStr("QRCode.png").c_str(), 0, 0, SW_SHOWNORMAL);
+
+ system("cls");
+ std::cout << XorStr("Press enter when you have scanned the QR code");
+ std::cin.get();
+
+ // remove the QR code
+ remove("QRCode.png");
+
+ system("cls");
+
+ std::cout << XorStr("Enter the code: ");
+
+ std::string code;
+ std::cin >> code;
+
+ instance.enable2fa(code);
+ }
+ else {
+
+ LI_FN(system)(XorStr("cls").c_str());
+
+ std::cout << XorStr("Enter the code to disable 2FA: ");
+
+ std::string code;
+ std::cin >> code;
+
+ instance.disable2fa(code);
+ }
+
+}
+
+void KeyAuth::api::web_login()
+{
+ checkInit();
+
+ // from https://perpetualprogrammers.wordpress.com/2016/05/22/the-http-server-api/
+
+ // Initialize the API.
+ ULONG result = 0;
+ HTTPAPI_VERSION version = HTTPAPI_VERSION_2;
+ result = HttpInitialize(version, HTTP_INITIALIZE_SERVER, 0);
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, "The Flags parameter contains an unsupported value.", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, "System error for Initialize", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Create server session.
+ HTTP_SERVER_SESSION_ID serverSessionId;
+ result = HttpCreateServerSession(version, &serverSessionId, 0);
+
+ if (result == ERROR_REVISION_MISMATCH) {
+ MessageBoxA(NULL, "Version for session invalid", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, "pServerSessionId parameter is null", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, "System error for HttpCreateServerSession", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Create URL group.
+ HTTP_URL_GROUP_ID groupId;
+ result = HttpCreateUrlGroup(serverSessionId, &groupId, 0);
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, "Url group create parameter error", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, "System error for HttpCreateUrlGroup", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Create request queue.
+ HANDLE requestQueueHandle;
+ result = HttpCreateRequestQueue(version, NULL, NULL, 0, &requestQueueHandle);
+
+ if (result == ERROR_REVISION_MISMATCH) {
+ MessageBoxA(NULL, "Wrong version", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, "Byte length exceeded", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_ALREADY_EXISTS) {
+ MessageBoxA(NULL, "pName already used", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_ACCESS_DENIED) {
+ MessageBoxA(NULL, "queue access denied", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_DLL_INIT_FAILED) {
+ MessageBoxA(NULL, "Initialize not called", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, "System error for HttpCreateRequestQueue", "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Attach request queue to URL group.
+ HTTP_BINDING_INFO info;
+ info.Flags.Present = 1;
+ info.RequestQueueHandle = requestQueueHandle;
+ result = HttpSetUrlGroupProperty(groupId, HttpServerBindingProperty, &info, sizeof(info));
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, XorStr("Invalid parameter").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, XorStr("System error for HttpSetUrlGroupProperty").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Add URLs to URL group.
+ PCWSTR url = L"http://localhost:1337/handshake";
+ result = HttpAddUrlToUrlGroup(groupId, url, 0, 0);
+
+ if (result == ERROR_ACCESS_DENIED) {
+ MessageBoxA(NULL, XorStr("No permissions to run web server").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_ALREADY_EXISTS) {
+ MessageBoxA(NULL, XorStr("You are running this program already").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_INVALID_PARAMETER) {
+ MessageBoxA(NULL, XorStr("ERROR_INVALID_PARAMETER for HttpAddUrlToUrlGroup").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result == ERROR_SHARING_VIOLATION) {
+ MessageBoxA(NULL, XorStr("Another program is using the webserver. Close Razer Chroma mouse software if you use that. Try to restart computer.").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ if (result != NO_ERROR) {
+ MessageBoxA(NULL, XorStr("System error for HttpAddUrlToUrlGroup").c_str(), "Error", MB_ICONEXCLAMATION);
+ LI_FN(exit)(0);
+ }
+
+ // Announce that it is running.
+ // wprintf(L"Listening. Please submit requests to: %s\n", url);
+
+ // req to: http://localhost:1337/handshake?user=mak&token=2f3e9eccc22ee583cf7bad86c751d865
+ bool going = true;
+ while (going == true)
+ {
+ // Wait for a request.
+ HTTP_REQUEST_ID requestId = 0;
+ HTTP_SET_NULL_ID(&requestId);
+ int bufferSize = 4096;
+ int requestSize = sizeof(HTTP_REQUEST) + bufferSize;
+ BYTE* buffer = new BYTE[requestSize];
+ PHTTP_REQUEST pRequest = (PHTTP_REQUEST)buffer;
+ RtlZeroMemory(buffer, requestSize);
+ ULONG bytesReturned;
+ result = HttpReceiveHttpRequest(
+ requestQueueHandle,
+ requestId,
+ HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ pRequest,
+ requestSize,
+ &bytesReturned,
+ NULL
+ );
+
+ // Display some information about the request.
+ // wprintf(L"Full URL: %ws\n", pRequest->CookedUrl.pFullUrl);
+ // wprintf(L" Path: %ws\n", pRequest->CookedUrl.pAbsPath);
+ // wprintf(L" Query: %ws\n", pRequest->CookedUrl.pQueryString);
+
+ std::wstring ws(pRequest->CookedUrl.pQueryString);
+ std::string myVarS = std::string(ws.begin(), ws.end());
+ std::string user = get_str_between_two_str(myVarS, "?user=", "&");
+ std::string token = get_str_between_two_str(myVarS, "&token=", "");
+
+ // std::cout << get_str_between_two_str(CW2A(pRequest->CookedUrl.pQueryString), "?", "&") << std::endl;
+
+ // break if preflight request from browser
+ if (pRequest->Verb == HttpVerbOPTIONS)
+ {
+ // Respond to the request.
+ HTTP_RESPONSE response;
+ RtlZeroMemory(&response, sizeof(response));
+
+ response.StatusCode = 200;
+ response.pReason = static_cast(XorStr("OK").c_str());
+ response.ReasonLength = (USHORT)strlen(response.pReason);
+
+ // https://social.msdn.microsoft.com/Forums/vstudio/en-US/6d468747-2221-4f4a-9156-f98f355a9c08/using-httph-to-set-up-an-https-server-that-is-queried-by-a-client-that-uses-cross-origin-requests?forum=vcgeneral
+ HTTP_UNKNOWN_HEADER accessControlHeader;
+ const char testCustomHeader[] = "Access-Control-Allow-Origin";
+ const char testCustomHeaderVal[] = "*";
+ accessControlHeader.pName = testCustomHeader;
+ accessControlHeader.NameLength = _countof(testCustomHeader) - 1;
+ accessControlHeader.pRawValue = testCustomHeaderVal;
+ accessControlHeader.RawValueLength = _countof(testCustomHeaderVal) - 1;
+ response.Headers.pUnknownHeaders = &accessControlHeader;
+ response.Headers.UnknownHeaderCount = 1;
+ // Add an entity chunk to the response.
+ // PSTR pEntityString = "Hello from C++";
+ HTTP_DATA_CHUNK dataChunk;
+ dataChunk.DataChunkType = HttpDataChunkFromMemory;
+
+ result = HttpSendHttpResponse(
+ requestQueueHandle,
+ pRequest->RequestId,
+ 0,
+ &response,
+ NULL,
+ NULL, // &bytesSent (optional)
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+
+ delete[]buffer;
+ continue;
+ }
+
+ // keyauth request
+ std::string hwid = utils::get_hwid();
+ auto data =
+ XorStr("type=login") +
+ XorStr("&username=") + user +
+ XorStr("&token=") + token +
+ XorStr("&hwid=") + hwid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto resp = req(data, api::url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, resp.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(resp);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ if (api::response.message != XorStr("Initialized").c_str()) {
+ LI_FN(GlobalAddAtomA)(seed.c_str());
+
+ std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed;
+ std::ofstream file(file_path);
+ if (file.is_open()) {
+ file << seed;
+ file.close();
+ }
+
+ std::string regPath = XorStr("Software\\").c_str() + seed;
+ HKEY hKey;
+ LONG result = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
+ if (result == ERROR_SUCCESS) {
+ LI_FN(RegSetValueExA)(hKey, seed.c_str(), 0, REG_SZ, reinterpret_cast(seed.c_str()), seed.size() + 1);
+ LI_FN(RegCloseKey)(hKey);
+ }
+
+ LI_FN(GlobalAddAtomA)(ownerid.c_str());
+ }
+ else {
+ LI_FN(exit)(12);
+ }
+
+ // Respond to the request.
+ HTTP_RESPONSE response;
+ RtlZeroMemory(&response, sizeof(response));
+
+ bool success = true;
+ if (json[(XorStr("success"))])
+ {
+ load_user_data(json[(XorStr("info"))]);
+
+ response.StatusCode = 420;
+ response.pReason = XorStr("SHEESH").c_str();
+ response.ReasonLength = (USHORT)strlen(response.pReason);
+ }
+ else
+ {
+ response.StatusCode = 200;
+ response.pReason = static_cast(json[(XorStr("message"))]).c_str();
+ response.ReasonLength = (USHORT)strlen(response.pReason);
+ success = false;
+ }
+ // end keyauth request
+
+ // https://social.msdn.microsoft.com/Forums/vstudio/en-US/6d468747-2221-4f4a-9156-f98f355a9c08/using-httph-to-set-up-an-https-server-that-is-queried-by-a-client-that-uses-cross-origin-requests?forum=vcgeneral
+ HTTP_UNKNOWN_HEADER accessControlHeader;
+ const char testCustomHeader[] = "Access-Control-Allow-Origin";
+ const char testCustomHeaderVal[] = "*";
+ accessControlHeader.pName = testCustomHeader;
+ accessControlHeader.NameLength = _countof(testCustomHeader) - 1;
+ accessControlHeader.pRawValue = testCustomHeaderVal;
+ accessControlHeader.RawValueLength = _countof(testCustomHeaderVal) - 1;
+ response.Headers.pUnknownHeaders = &accessControlHeader;
+ response.Headers.UnknownHeaderCount = 1;
+ // Add an entity chunk to the response.
+ // PSTR pEntityString = "Hello from C++";
+ HTTP_DATA_CHUNK dataChunk;
+ dataChunk.DataChunkType = HttpDataChunkFromMemory;
+
+ result = HttpSendHttpResponse(
+ requestQueueHandle,
+ pRequest->RequestId,
+ 0,
+ &response,
+ NULL,
+ NULL, // &bytesSent (optional)
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+
+ if (result == NO_ERROR) {
+ going = false;
+ }
+
+ delete[]buffer;
+
+ if (!success)
+ LI_FN(exit)(0);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+ }
+}
+
+void KeyAuth::api::button(std::string button)
+{
+ checkInit();
+
+ // from https://perpetualprogrammers.wordpress.com/2016/05/22/the-http-server-api/
+
+ // Initialize the API.
+ ULONG result = 0;
+ HTTPAPI_VERSION version = HTTPAPI_VERSION_2;
+ result = HttpInitialize(version, HTTP_INITIALIZE_SERVER, 0);
+
+ // Create server session.
+ HTTP_SERVER_SESSION_ID serverSessionId;
+ result = HttpCreateServerSession(version, &serverSessionId, 0);
+
+ // Create URL group.
+ HTTP_URL_GROUP_ID groupId;
+ result = HttpCreateUrlGroup(serverSessionId, &groupId, 0);
+
+ // Create request queue.
+ HANDLE requestQueueHandle;
+ result = HttpCreateRequestQueue(version, NULL, NULL, 0, &requestQueueHandle);
+
+ // Attach request queue to URL group.
+ HTTP_BINDING_INFO info;
+ info.Flags.Present = 1;
+ info.RequestQueueHandle = requestQueueHandle;
+ result = HttpSetUrlGroupProperty(groupId, HttpServerBindingProperty, &info, sizeof(info));
+
+ // Add URLs to URL group.
+ std::wstring output;
+ output = std::wstring(button.begin(), button.end());
+ output = std::wstring(L"http://localhost:1337/") + output;
+ PCWSTR url = output.c_str();
+ result = HttpAddUrlToUrlGroup(groupId, url, 0, 0);
+
+ // Announce that it is running.
+ // wprintf(L"Listening. Please submit requests to: %s\n", url);
+
+ // req to: http://localhost:1337/buttonvaluehere
+ bool going = true;
+ while (going == true)
+ {
+ // Wait for a request.
+ HTTP_REQUEST_ID requestId = 0;
+ HTTP_SET_NULL_ID(&requestId);
+ int bufferSize = 4096;
+ int requestSize = sizeof(HTTP_REQUEST) + bufferSize;
+ BYTE* buffer = new BYTE[requestSize];
+ PHTTP_REQUEST pRequest = (PHTTP_REQUEST)buffer;
+ RtlZeroMemory(buffer, requestSize);
+ ULONG bytesReturned;
+ result = HttpReceiveHttpRequest(
+ requestQueueHandle,
+ requestId,
+ HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ pRequest,
+ requestSize,
+ &bytesReturned,
+ NULL
+ );
+
+ going = false;
+
+ // Display some information about the request.
+ // wprintf(L"Full URL: %ws\n", pRequest->CookedUrl.pFullUrl);
+ // wprintf(L" Path: %ws\n", pRequest->CookedUrl.pAbsPath);
+ // wprintf(L" Query: %ws\n", pRequest->CookedUrl.pQueryString);
+
+ // std::cout << get_str_between_two_str(CW2A(pRequest->CookedUrl.pQueryString), "?", "&") << std::endl;
+
+ // Break from the loop if it's the poison pill (a DELETE request).
+ // if (pRequest->Verb == HttpVerbDELETE)
+ // {
+ // wprintf(L"Asked to stop.\n");
+ // break;
+ // }
+
+ // Respond to the request.
+ HTTP_RESPONSE response;
+ RtlZeroMemory(&response, sizeof(response));
+ response.StatusCode = 420;
+ response.pReason = XorStr("SHEESH").c_str();
+ response.ReasonLength = (USHORT)strlen(response.pReason);
+
+ // https://social.msdn.microsoft.com/Forums/vstudio/en-US/6d468747-2221-4f4a-9156-f98f355a9c08/using-httph-to-set-up-an-https-server-that-is-queried-by-a-client-that-uses-cross-origin-requests?forum=vcgeneral
+ HTTP_UNKNOWN_HEADER accessControlHeader;
+ const char testCustomHeader[] = "Access-Control-Allow-Origin";
+ const char testCustomHeaderVal[] = "*";
+ accessControlHeader.pName = testCustomHeader;
+ accessControlHeader.NameLength = _countof(testCustomHeader) - 1;
+ accessControlHeader.pRawValue = testCustomHeaderVal;
+ accessControlHeader.RawValueLength = _countof(testCustomHeaderVal) - 1;
+ response.Headers.pUnknownHeaders = &accessControlHeader;
+ response.Headers.UnknownHeaderCount = 1;
+ // Add an entity chunk to the response.
+ // PSTR pEntityString = "Hello from C++";
+ HTTP_DATA_CHUNK dataChunk;
+ dataChunk.DataChunkType = HttpDataChunkFromMemory;
+
+ result = HttpSendHttpResponse(
+ requestQueueHandle,
+ pRequest->RequestId,
+ 0,
+ &response,
+ NULL,
+ NULL, // &bytesSent (optional)
+ NULL,
+ 0,
+ NULL,
+ NULL
+ );
+
+ delete[]buffer;
+ }
+}
+
+void KeyAuth::api::regstr(std::string username, std::string password, std::string key, std::string email) {
+ checkInit();
+
+ std::string hwid = utils::get_hwid();
+ auto data =
+ XorStr("type=register") +
+ XorStr("&username=") + username +
+ XorStr("&pass=") + password +
+ XorStr("&key=") + key +
+ XorStr("&email=") + email +
+ XorStr("&hwid=") + hwid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+
+ load_response_data(json);
+ if (json[(XorStr("success"))])
+ load_user_data(json[(XorStr("info"))]);
+
+ if (api::response.message != XorStr("Initialized").c_str()) {
+ LI_FN(GlobalAddAtomA)(seed.c_str());
+
+ std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed;
+ std::ofstream file(file_path);
+ if (file.is_open()) {
+ file << seed;
+ file.close();
+ }
+
+ std::string regPath = XorStr("Software\\").c_str() + seed;
+ HKEY hKey;
+ LONG result = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
+ if (result == ERROR_SUCCESS) {
+ LI_FN(RegSetValueExA)(hKey, seed.c_str(), 0, REG_SZ, reinterpret_cast(seed.c_str()), seed.size() + 1);
+ LI_FN(RegCloseKey)(hKey);
+ }
+
+ LI_FN(GlobalAddAtomA)(ownerid.c_str());
+ }
+ else {
+ LI_FN(exit)(12);
+ }
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else
+ {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::upgrade(std::string username, std::string key) {
+ checkInit();
+
+ auto data =
+ XorStr("type=upgrade") +
+ XorStr("&username=") + username +
+ XorStr("&key=") + key +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+
+ json[(XorStr("success"))] = false;
+ load_response_data(json);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+std::string generate_random_number() {
+ std::random_device rd;
+ std::mt19937 gen(rd());
+ std::uniform_int_distribution<> dist_length(5, 10); // Random length between 5 and 10 digits
+ std::uniform_int_distribution<> dist_digit(0, 9); // Random digit
+
+ int length = dist_length(gen);
+ std::string random_number;
+ for (int i = 0; i < length; ++i) {
+ random_number += std::to_string(dist_digit(gen));
+ }
+ return random_number;
+}
+
+void KeyAuth::api::license(std::string key, std::string code) {
+ // Call threads to start in 15 seconds..
+ CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkAtoms, 0, 0, 0);
+ CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkFiles, 0, 0, 0);
+ CreateThread(0, 0, (LPTHREAD_START_ROUTINE)checkRegistry, 0, 0, 0);
+
+ checkInit();
+
+ std::string hwid = utils::get_hwid();
+ auto data =
+ XorStr("type=license") +
+ XorStr("&key=") + key +
+ XorStr("&code=") + code +
+ XorStr("&hwid=") + hwid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ if (json[(XorStr("success"))])
+ load_user_data(json[(XorStr("info"))]);
+
+ if (api::response.message != XorStr("Initialized").c_str()) {
+ LI_FN(GlobalAddAtomA)(seed.c_str());
+
+ std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed;
+ std::ofstream file(file_path);
+ if (file.is_open()) {
+ file << seed;
+ file.close();
+ }
+
+ std::string regPath = XorStr("Software\\").c_str() + seed;
+ HKEY hKey;
+ LONG result = RegCreateKeyExA(HKEY_CURRENT_USER, regPath.c_str(), 0, NULL, 0, KEY_WRITE, NULL, &hKey, NULL);
+ if (result == ERROR_SUCCESS) {
+ LI_FN(RegSetValueExA)(hKey, seed.c_str(), 0, REG_SZ, reinterpret_cast(seed.c_str()), seed.size() + 1);
+ LI_FN(RegCloseKey)(hKey);
+ }
+
+ LI_FN(GlobalAddAtomA)(ownerid.c_str());
+ }
+ else {
+ LI_FN(exit)(12);
+ }
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::setvar(std::string var, std::string vardata) {
+ checkInit();
+
+ auto data =
+ XorStr("type=setvar") +
+ XorStr("&var=") + var +
+ XorStr("&data=") + vardata +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ load_response_data(json);
+}
+
+std::string KeyAuth::api::getvar(std::string var) {
+ checkInit();
+
+ auto data =
+ XorStr("type=getvar") +
+ XorStr("&var=") + var +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ return !json[(XorStr("response"))].is_null() ? json[(XorStr("response"))] : XorStr("");
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::ban(std::string reason) {
+ checkInit();
+
+ auto data =
+ XorStr("type=ban") +
+ XorStr("&reason=") + reason +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else
+ {
+ LI_FN(exit)(7);
+ }
+}
+
+bool KeyAuth::api::checkblack() {
+ checkInit();
+
+ std::string hwid = utils::get_hwid();
+ auto data =
+ XorStr("type=checkblacklist") +
+ XorStr("&hwid=") + hwid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ return json[("success")];
+ }
+ LI_FN(exit)(9);
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::check(bool check_paid) {
+ checkInit();
+
+ auto data =
+ XorStr("type=check") +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ std::string endpoint = url;
+ if (check_paid) {
+ endpoint += "?check_paid=1";
+ }
+
+ auto response = req(data, endpoint);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+std::string KeyAuth::api::var(std::string varid) {
+ checkInit();
+
+ auto data =
+ XorStr("type=var") +
+ XorStr("&varid=") + varid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ load_response_data(json);
+ return json[(XorStr("message"))];
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::log(std::string message) {
+ checkInit();
+
+ char acUserName[100];
+ DWORD nUserName = sizeof(acUserName);
+ GetUserNameA(acUserName, &nUserName);
+ std::string UsernamePC = acUserName;
+
+ auto data =
+ XorStr("type=log") +
+ XorStr("&pcuser=") + UsernamePC +
+ XorStr("&message=") + message +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ req(data, url);
+}
+
+std::vector KeyAuth::api::download(std::string fileid) {
+ checkInit();
+
+ auto to_uc_vector = [](std::string value) {
+ return std::vector(value.data(), value.data() + value.length() );
+ };
+
+
+ auto data =
+ XorStr("type=file") +
+ XorStr("&fileid=") + fileid +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=").c_str() + ownerid;
+
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ std::string message = json[(XorStr("message"))];
+
+ load_response_data(json);
+ if (json[ XorStr( "success" ) ])
+ {
+ auto file = hexDecode(json[ XorStr( "contents" )]);
+ return to_uc_vector(file);
+ }
+ return {};
+}
+
+
+std::string KeyAuth::api::webhook(std::string id, std::string params, std::string body, std::string contenttype)
+{
+ checkInit();
+
+ CURL *curl = curl_easy_init();
+ auto data =
+ XorStr("type=webhook") +
+ XorStr("&webid=") + id +
+ XorStr("¶ms=") + curl_easy_escape(curl, params.c_str(), 0) +
+ XorStr("&body=") + curl_easy_escape(curl, body.c_str(), 0) +
+ XorStr("&conttype=") + contenttype +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ curl_easy_cleanup(curl);
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+
+ load_response_data(json);
+ return !json[(XorStr("response"))].is_null() ? json[(XorStr("response"))] : XorStr("");
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+std::string KeyAuth::api::fetchonline()
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=fetchOnline") +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+ std::string onlineusers;
+
+ int y = atoi(api::app_data.numOnlineUsers.c_str());
+ for (int i = 0; i < y; i++)
+ {
+ onlineusers.append(json[XorStr("users")][i][XorStr("credential")]); onlineusers.append(XorStr("\n"));
+ }
+
+ return onlineusers;
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::fetchstats()
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=fetchStats") +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+
+ auto response = req(data, url);
+ std::hash hasher;
+ int expectedHash = hasher(42);
+ int result = VerifyPayload(signature, signatureTimestamp, response.data());
+ if ((hasher(result ^ 0xA5A5) & 0xFFFF) == (expectedHash & 0xFFFF))
+ {
+
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("ownerid"))] != ownerid) {
+ LI_FN(exit)(8);
+ }
+
+ std::string message = json[(XorStr("message"))];
+
+ std::hash hasher;
+ size_t expectedHash = hasher(68);
+ size_t resultCode = hasher(json[(XorStr("code"))]);
+
+ if (!json[(XorStr("success"))] || (json[(XorStr("success"))] && (resultCode == expectedHash))) {
+
+ load_response_data(json);
+
+ if (json[(XorStr("success"))])
+ load_app_data(json[(XorStr("appinfo"))]);
+ }
+ else {
+ LI_FN(exit)(9);
+ }
+ }
+ else {
+ LI_FN(exit)(7);
+ }
+}
+
+void KeyAuth::api::forgot(std::string username, std::string email)
+{
+ checkInit();
+
+ auto data =
+ XorStr("type=forgot") +
+ XorStr("&username=") + username +
+ XorStr("&email=") + email +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ load_response_data(json);
+}
+
+void KeyAuth::api::logout() {
+ checkInit();
+
+ auto data =
+ XorStr("type=logout") +
+ XorStr("&sessionid=") + sessionid +
+ XorStr("&name=") + name +
+ XorStr("&ownerid=") + ownerid;
+ auto response = req(data, url);
+ auto json = response_decoder.parse(response);
+ if (json[(XorStr("success"))]) {
+
+ //clear all old user data from program
+ user_data.createdate.clear();
+ user_data.ip.clear();
+ user_data.hwid.clear();
+ user_data.lastlogin.clear();
+ user_data.username.clear();
+ user_data.subscriptions.clear();
+
+ //clear sessionid
+ sessionid.clear();
+
+ //clear enckey
+ enckey.clear();
+
+ }
+
+ load_response_data(json);
+}
+
+int VerifyPayload(std::string signature, std::string timestamp, std::string body)
+{
+ // Step 1: Convert the string to a long long integer
+ long long unix_timestamp = std::stoll(timestamp);
+
+ // Step 2: Get the current time as Unix timestamp (seconds since epoch)
+ auto current_time = std::chrono::system_clock::now();
+ long long current_unix_time = std::chrono::duration_cast(
+ current_time.time_since_epoch()).count();
+
+ // Step 3: Compare the timestamps
+ if (current_unix_time - unix_timestamp > 20) {
+ // std::cout << "The timestamp is older than 20 seconds." << std::endl;
+ LI_FN(exit)(3);
+ }
+
+ if (sodium_init() < 0) {
+ // std::cerr << "Failed to initialize sodium" << std::endl;
+ LI_FN(exit)(4);
+ }
+
+ std::string message = timestamp + body;
+
+ unsigned char sig[64];
+ unsigned char pk[32];
+ if (sodium_hex2bin(sig, sizeof(sig), signature.c_str(), signature.length(), NULL, NULL, NULL) != 0)
+ {
+ // std::cerr << "Invalid signature format" << std::endl;
+ LI_FN(exit)(5);
+ }
+
+ if (sodium_hex2bin(pk, sizeof(pk), API_PUBLIC_KEY.c_str(), API_PUBLIC_KEY.length(), NULL, NULL, NULL) != 0)
+ {
+ // std::cerr << "Invalid public key format" << std::endl;
+ LI_FN(exit)(6);
+ };
+
+ if (crypto_sign_ed25519_verify_detached(sig, reinterpret_cast(message.c_str()), message.length(), pk) != 0)
+ {
+ // std::cerr << "Signature verification failed" << std::endl;
+ LI_FN(exit)(7);
+ }
+
+ // std::cout << "\n Payload verfied" << std::endl;
+
+ int value = 42 ^ 0xA5A5;
+ return value & 0xFFFF;
+}
+
+// credits https://stackoverflow.com/a/3790661
+static std::string hexDecode(const std::string& hex)
+{
+ int len = hex.length();
+ std::string newString;
+ for (int i = 0; i < len; i += 2)
+ {
+ std::string byte = hex.substr(i, 2);
+ char chr = (char)(int)strtol(byte.c_str(), NULL, 16);
+ newString.push_back(chr);
+ }
+ return newString;
+}
+// credits https://stackoverflow.com/a/43002794
+std::string get_str_between_two_str(const std::string& s,
+ const std::string& start_delim,
+ const std::string& stop_delim)
+{
+ unsigned first_delim_pos = s.find(start_delim);
+ unsigned end_pos_of_first_delim = first_delim_pos + start_delim.length();
+ unsigned last_delim_pos = s.find(stop_delim);
+
+ return s.substr(end_pos_of_first_delim,
+ last_delim_pos - end_pos_of_first_delim);
+}
+
+std::string KeyAuth::api::req(std::string data, std::string url) {
+ CURL* curl = curl_easy_init();
+ if (!curl)
+ return XorStr("null");
+
+ std::string to_return;
+ std::string headers;
+
+ curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
+
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1);
+
+ curl_easy_setopt(curl, CURLOPT_NOPROXY, XorStr( "keyauth.win" ) );
+
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L);
+ curl_easy_setopt(curl, CURLOPT_CERTINFO, 1L);
+
+ curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data.c_str());
+
+ curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_callback);
+ curl_easy_setopt(curl, CURLOPT_WRITEDATA, &to_return);
+
+ curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback);
+ curl_easy_setopt(curl, CURLOPT_HEADERDATA, &headers);
+
+ auto code = curl_easy_perform(curl);
+
+ if (code != CURLE_OK)
+ error(curl_easy_strerror(code));
+
+ debugInfo(data, url, to_return, "Sig: " + signature + "\nTimestamp:" + signatureTimestamp);
+
+ return to_return;
+}
+void error(std::string message) {
+ system((XorStr("start cmd /C \"color b && title Error && echo ").c_str() + message + XorStr(" && timeout /t 5\"")).c_str());
+ LI_FN(__fastfail)(0);
+}
+// code submitted in pull request from https://github.com/Roblox932
+auto check_section_integrity( const char *section_name, bool fix = false ) -> bool
+{
+ const auto map_file = []( HMODULE hmodule ) -> std::tuple
+ {
+ wchar_t filename[ MAX_PATH ];
+ DWORD size = MAX_PATH;
+ QueryFullProcessImageName(GetCurrentProcess(), 0, filename, &size);
+
+
+ const auto file_handle = CreateFile( filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0 );
+ if ( !file_handle || file_handle == INVALID_HANDLE_VALUE )
+ {
+ return { 0ull, nullptr };
+ }
+
+ const auto file_mapping = CreateFileMapping( file_handle, 0, PAGE_READONLY, 0, 0, 0 );
+ if ( !file_mapping )
+ {
+ CloseHandle( file_handle );
+ return { 0ull, nullptr };
+ }
+
+ return { reinterpret_cast< std::uintptr_t >( MapViewOfFile( file_mapping, FILE_MAP_READ, 0, 0, 0 ) ), file_handle };
+ };
+
+ const auto hmodule = GetModuleHandle( 0 );
+ if ( !hmodule ) return true;
+
+ const auto base_0 = reinterpret_cast< std::uintptr_t >( hmodule );
+ if ( !base_0 ) return true;
+
+ const auto dos_0 = reinterpret_cast< IMAGE_DOS_HEADER * >( base_0 );
+ if ( dos_0->e_magic != IMAGE_DOS_SIGNATURE ) return true;
+
+ const auto nt_0 = reinterpret_cast< IMAGE_NT_HEADERS * >( base_0 + dos_0->e_lfanew );
+ if ( nt_0->Signature != IMAGE_NT_SIGNATURE ) return true;
+
+ auto section_0 = IMAGE_FIRST_SECTION( nt_0 );
+
+ const auto [base_1, file_handle] = map_file( hmodule );
+ if ( !base_1 || !file_handle || file_handle == INVALID_HANDLE_VALUE ) return true;
+
+ const auto dos_1 = reinterpret_cast< IMAGE_DOS_HEADER * >( base_1 );
+ if ( dos_1->e_magic != IMAGE_DOS_SIGNATURE )
+ {
+ UnmapViewOfFile( reinterpret_cast< void * >( base_1 ) );
+ CloseHandle( file_handle );
+ return true;
+ }
+
+ const auto nt_1 = reinterpret_cast< IMAGE_NT_HEADERS * >( base_1 + dos_1->e_lfanew );
+ if ( nt_1->Signature != IMAGE_NT_SIGNATURE ||
+ nt_1->FileHeader.TimeDateStamp != nt_0->FileHeader.TimeDateStamp ||
+ nt_1->FileHeader.NumberOfSections != nt_0->FileHeader.NumberOfSections )
+ {
+ UnmapViewOfFile( reinterpret_cast< void * >( base_1 ) );
+ CloseHandle( file_handle );
+ return true;
+ }
+
+ auto section_1 = IMAGE_FIRST_SECTION( nt_1 );
+
+ bool patched = false;
+ for ( auto i = 0; i < nt_1->FileHeader.NumberOfSections; ++i, ++section_0, ++section_1 )
+ {
+ if ( strcmp( reinterpret_cast< char * >( section_0->Name ), section_name ) ||
+ !( section_0->Characteristics & IMAGE_SCN_MEM_EXECUTE ) ) continue;
+
+ for ( auto i = 0u; i < section_0->SizeOfRawData; ++i )
+ {
+ const auto old_value = *reinterpret_cast< BYTE * >( base_1 + section_1->PointerToRawData + i );
+
+ if ( *reinterpret_cast< BYTE * >( base_0 + section_0->VirtualAddress + i ) == old_value )
+ {
+ continue;
+ }
+
+ if ( fix )
+ {
+ DWORD new_protect { PAGE_EXECUTE_READWRITE }, old_protect;
+ VirtualProtect( ( void * )( base_0 + section_0->VirtualAddress + i ), sizeof( BYTE ), new_protect, &old_protect );
+ *reinterpret_cast< BYTE * >( base_0 + section_0->VirtualAddress + i ) = old_value;
+ VirtualProtect( ( void * )( base_0 + section_0->VirtualAddress + i ), sizeof( BYTE ), old_protect, &new_protect );
+ }
+
+ patched = true;
+ }
+
+ break;
+ }
+
+ UnmapViewOfFile( reinterpret_cast< void * >( base_1 ) );
+ CloseHandle( file_handle );
+
+ return patched;
+}
+
+void runChecks() {
+ Sleep(45000); // give people 1 minute to login. (because the functions we call already wait 15 seconds)
+
+ checkAtoms();
+ checkFiles();
+ checkRegistry();
+}
+
+void checkAtoms() {
+ Sleep(15000); // enough time for API response, even on slower connections
+
+ while (true) {
+ if (LI_FN(GlobalFindAtomA)(seed.c_str()) == 0) {
+ LI_FN(exit)(13);
+ LI_FN(__fastfail)(0);
+ }
+ Sleep(1000); // thread interval
+ }
+}
+
+void checkFiles() {
+ Sleep(15000); // enough time for API response, even on slower connections
+
+ while (true) {
+ std::string file_path = XorStr("C:\\ProgramData\\").c_str() + seed;
+ DWORD file_attr = LI_FN(GetFileAttributesA)(file_path.c_str());
+ if (file_attr == INVALID_FILE_ATTRIBUTES || (file_attr & FILE_ATTRIBUTE_DIRECTORY)) {
+ LI_FN(exit)(14);
+ LI_FN(__fastfail)(0);
+ }
+ Sleep(2000); // thread interval, files are more intensive than Atom tables which use memory
+ }
+}
+
+void checkRegistry() {
+ Sleep(15000); // enough time for API response, even on slower connections
+
+ while (true) {
+ std::string regPath = XorStr("Software\\").c_str() + seed;
+ HKEY hKey;
+ LONG result = LI_FN(RegOpenKeyExA)(HKEY_CURRENT_USER, regPath.c_str(), 0, KEY_READ, &hKey);
+ if (result != ERROR_SUCCESS) {
+ LI_FN(exit)(15);
+ LI_FN(__fastfail)(0);
+ }
+ LI_FN(RegCloseKey)(hKey);
+ }
+ Sleep(1500); // thread interval
+}
+
+std::string checksum()
+{
+ auto exec = [&](const char* cmd) -> std::string
+ {
+ uint16_t line = -1;
+ std::array buffer;
+ std::string result;
+ std::unique_ptr pipe(_popen(cmd, "r"), _pclose);
+ if (!pipe) {
+ throw std::runtime_error(XorStr("popen() failed!"));
+ }
+
+ while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
+ result = buffer.data();
+ }
+ return result;
+ };
+
+ char rawPathName[MAX_PATH];
+ GetModuleFileNameA(NULL, rawPathName, MAX_PATH);
+
+ return exec(("certutil -hashfile \"" + std::string(rawPathName) + XorStr( "\" MD5 | find /i /v \"md5\" | find /i /v \"certutil\"") ).c_str());
+}
+
+std::string getPath() {
+ const char* programDataPath = std::getenv("ALLUSERSPROFILE");
+
+ if (programDataPath != nullptr) {
+ return std::string(programDataPath);
+ }
+ else {
+
+ return std::filesystem::current_path().string();
+ }
+}
+
+void RedactField(nlohmann::json& jsonObject, const std::string& fieldName)
+{
+
+ if (jsonObject.contains(fieldName)) {
+ jsonObject[fieldName] = "REDACTED";
+ }
+}
+
+void debugInfo(std::string data, std::string url, std::string response, std::string headers) {
+ // output debug logs to C:\ProgramData\KeyAuth\Debug\
+
+ std::string redacted_response = "n/a";
+ // for logging the headers, since response is not avaliable there
+ if (response != "n/a") {
+ //turn response into json
+ nlohmann::json responses = nlohmann::json::parse(response);
+ RedactField(responses, "sessionid");
+ RedactField(responses, "ownerid");
+ RedactField(responses, "app");
+ RedactField(responses, "name");
+ RedactField(responses, "contents");
+ RedactField(responses, "key");
+ RedactField(responses, "username");
+ RedactField(responses, "password");
+ RedactField(responses, "version");
+ RedactField(responses, "fileid");
+ RedactField(responses, "webhooks");
+ redacted_response = responses.dump();
+ }
+
+ std::string redacted_data = "n/a";
+ // for logging the headers, since request JSON is not avaliable there
+ if (data != "n/a") {
+ //turn data into json
+ std::replace(data.begin(), data.end(), '&', ' ');
+
+ nlohmann::json datas;
+
+ std::istringstream iss(data);
+ std::vector results((std::istream_iterator(iss)),
+ std::istream_iterator());
+
+ for (auto const& value : results) {
+ datas[value.substr(0, value.find('='))] = value.substr(value.find('=') + 1);
+ }
+
+ RedactField(datas, "sessionid");
+ RedactField(datas, "ownerid");
+ RedactField(datas, "app");
+ RedactField(datas, "name");
+ RedactField(datas, "key");
+ RedactField(datas, "username");
+ RedactField(datas, "password");
+ RedactField(datas, "contents");
+ RedactField(datas, "version");
+ RedactField(datas, "fileid");
+ RedactField(datas, "webhooks");
+
+ redacted_data = datas.dump();
+ }
+
+ //gets the path
+ std::string path = getPath();
+
+ //fetch filename
+
+ TCHAR filename[MAX_PATH];
+ GetModuleFileName(NULL, filename, MAX_PATH);
+
+ TCHAR* filename_only = PathFindFileName(filename);
+
+ std::wstring filenameOnlyString(filename_only);
+
+ std::string filenameOnly(filenameOnlyString.begin(), filenameOnlyString.end());
+
+ ///////////////////////
+
+ //creates variables for the paths needed :smile:
+ std::string KeyAuthPath = path + "\\KeyAuth";
+ std::string logPath = KeyAuthPath + "\\Debug\\" + filenameOnly.substr(0, filenameOnly.size() - 4);
+
+ //basically loops until we have all the paths
+ if (!std::filesystem::exists(KeyAuthPath) || !std::filesystem::exists(KeyAuthPath + "\\Debug") || !std::filesystem::exists(logPath)) {
+
+ if (!std::filesystem::exists(KeyAuthPath)) { std::filesystem::create_directory(KeyAuthPath); }
+
+ if (!std::filesystem::exists(KeyAuthPath + "\\Debug")) { std::filesystem::create_directory(KeyAuthPath + "\\Debug"); }
+
+ if (!std::filesystem::exists(logPath)) { std::filesystem::create_directory(logPath); }
+
+ }
+
+ if (response.length() >= 500) { return; }
+
+ //fetch todays time
+ std::time_t t = std::time(nullptr);
+ char time[80];
+
+ std::tm* localTime = std::localtime(&t);
+
+ std::strftime(time, sizeof(time), "%m-%d-%Y", localTime);
+
+ std::ofstream logfile(logPath + "\\" + time + ".txt", std::ios::app);
+
+ //get time
+ int hours = localTime->tm_hour;
+ int minutes = localTime->tm_min;
+
+ std::string period;
+ if (hours < 12) {
+ period = "AM";
+ }
+ else {
+ period = "PM";
+ hours -= 12;
+ }
+
+ std::string formattedMinutes = (minutes < 10) ? "0" + std::to_string(minutes) : std::to_string(minutes);
+
+ std::string currentTimeString = std::to_string(hours) + ":" + formattedMinutes + " " + period;
+
+ std::string contents = "\n\n@ " + currentTimeString + "\nURL: " + url + "\nData sent : " + redacted_data + "\nResponse : " + redacted_response + "\n" + headers;
+
+ logfile << contents;
+
+ logfile.close();
+}
+
+void checkInit() {
+ if (!initialized) {
+ error(XorStr("You need to run the KeyAuthApp.init(); function before any other KeyAuth functions"));
+ }
+}
+// code submitted in pull request from https://github.com/BINM7MD
+BOOL bDataCompare(const BYTE* pData, const BYTE* bMask, const char* szMask)
+{
+ for (; *szMask; ++szMask, ++pData, ++bMask)
+ {
+ if (*szMask == 'x' && *pData != *bMask)
+ return FALSE;
+ }
+ return (*szMask) == NULL;
+}
+DWORD64 FindPattern(BYTE* bMask, const char* szMask)
+{
+ MODULEINFO mi{ };
+ GetModuleInformation(GetCurrentProcess(), GetModuleHandleA(NULL), &mi, sizeof(mi));
+
+ DWORD64 dwBaseAddress = DWORD64(mi.lpBaseOfDll);
+ const auto dwModuleSize = mi.SizeOfImage;
+
+ for (auto i = 0ul; i < dwModuleSize; i++)
+ {
+ if (bDataCompare(PBYTE(dwBaseAddress + i), bMask, szMask))
+ return DWORD64(dwBaseAddress + i);
+ }
+ return NULL;
+}
+
+DWORD64 Function_Address;
+void modify()
+{
+ // code submitted in pull request from https://github.com/Roblox932
+ check_section_integrity( XorStr( ".text" ).c_str( ), true );
+
+ while (true)
+ {
+ // new code by https://github.com/LiamG53
+ protection::init();
+ // ^ check for jumps, break points (maybe useless), return address.
+
+ if ( check_section_integrity( XorStr( ".text" ).c_str( ), false ) )
+ {
+ error(XorStr("check_section_integrity() failed, don't tamper with the program."));
+ }
+ // code submitted in pull request from https://github.com/sbtoonz, authored by KeePassXC https://github.com/keepassxreboot/keepassxc/blob/dab7047113c4ad4ffead944d5c4ebfb648c1d0b0/src/core/Bootstrap.cpp#L121
+ if(!LockMemAccess())
+ {
+ error(XorStr("LockMemAccess() failed, don't tamper with the program."));
+ }
+ // code submitted in pull request from https://github.com/BINM7MD
+ if (Function_Address == NULL) {
+ Function_Address = FindPattern(PBYTE("\x48\x89\x74\x24\x00\x57\x48\x81\xec\x00\x00\x00\x00\x49\x8b\xf0"), XorStr("xxxx?xxxx????xxx").c_str()) - 0x5;
+ }
+ BYTE Instruction = *(BYTE*)Function_Address;
+
+ if ((DWORD64)Instruction == 0xE9) {
+ error(XorStr("Pattern checksum failed, don't tamper with the program."));
+ }
+ Sleep(50);
+ }
+}
diff --git a/auth.hpp b/auth.hpp
new file mode 100644
index 0000000..53bd10e
--- /dev/null
+++ b/auth.hpp
@@ -0,0 +1,164 @@
+#include
+#include
+#include
+
+#define CURL_STATICLIB
+
+struct channel_struct
+{
+ std::string author;
+ std::string message;
+ std::string timestamp;
+};
+
+namespace KeyAuth {
+ class api {
+ public:
+
+ std::string name, ownerid, version, url, path;
+
+ api(std::string name, std::string ownerid, std::string version, std::string url, std::string path) : name(name), ownerid(ownerid), version(version), url(url), path(path) {}
+
+ void ban(std::string reason = "");
+ void init();
+ void check(bool check_paid = false);
+ void log(std::string msg);
+ void license(std::string key, std::string code = "");
+ std::string var(std::string varid);
+ std::string webhook(std::string id, std::string params, std::string body = "", std::string contenttype = "");
+ void setvar(std::string var, std::string vardata);
+ std::string getvar(std::string var);
+ bool checkblack();
+ void web_login();
+ void button(std::string value);
+ void upgrade(std::string username, std::string key);
+ void login(std::string username, std::string password, std::string code = "");
+ std::vector