mirror of
https://github.com/redstrate/Astra.git
synced 2025-04-23 12:57:45 +00:00
Add option to generate OTP codes automatically
* This uses the great libcotp library, I stripped it down to fit inside the repository. * This is a security-convenience trade-off, and it's made very clear with the tooltips on the settings page. * It's still secured by your system keychain, and it's up to the users whether that's good enough for them. Eventually down the line I would like to support more esoteric keychains such as Bitwarden or KeePass. * Right now it's only integrated into the auto-login desktop feature, but there will eventually be like an "auto-fill OTP" button in the main window. There's still a lot to clean up with these new features but they work a little at least :-)
This commit is contained in:
parent
540c8b6f80
commit
5ee036dd09
21 changed files with 1596 additions and 7 deletions
3
external/CMakeLists.txt
vendored
3
external/CMakeLists.txt
vendored
|
@ -1,3 +1,6 @@
|
|||
add_subdirectory(libbaseencode)
|
||||
add_subdirectory(libcotp)
|
||||
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
|
|
37
external/libbaseencode/.gitignore
vendored
Normal file
37
external/libbaseencode/.gitignore
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
.idea/
|
||||
cmake-build-debug/
|
||||
build/
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
||||
*.su
|
24
external/libbaseencode/CMakeLists.txt
vendored
Normal file
24
external/libbaseencode/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(baseencode)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# set up versioning.
|
||||
set(BUILD_MAJOR "1")
|
||||
set(BUILD_MINOR "0")
|
||||
set(BUILD_VERSION "14")
|
||||
set(BUILD_VERSION ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_VERSION})
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
set(BASEENCODE_HEADERS src/baseencode.h)
|
||||
set(SOURCE_FILES src/base32.c src/base64.c)
|
||||
|
||||
set(CMAKE_C_FLAGS "-Wall -Werror -fPIC")
|
||||
|
||||
add_library(${PROJECT_NAME} SHARED ${SOURCE_FILES})
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} ${PROJECT_LIBS})
|
||||
target_include_directories(${PROJECT_NAME} PUBLIC src)
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR})
|
201
external/libbaseencode/LICENSE
vendored
Normal file
201
external/libbaseencode/LICENSE
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 Paolo Stivanin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
41
external/libbaseencode/README.md
vendored
Normal file
41
external/libbaseencode/README.md
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
# libbaseencode
|
||||
<a href="https://scan.coverity.com/projects/paolostivanin-libbaseencode">
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://scan.coverity.com/projects/12747/badge.svg"/>
|
||||
</a>
|
||||
|
||||
Library written in C for encoding and decoding data using base32 or base64 according to [RFC-4648](https://tools.ietf.org/html/rfc4648)
|
||||
|
||||
# Requiremens
|
||||
- GCC or Clang
|
||||
- CMake
|
||||
|
||||
# Build and Install
|
||||
```
|
||||
$ git clone https://github.com/paolostivanin/libbaseencode.git
|
||||
$ cd libbaseencode
|
||||
$ mkdir build && cd $_
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../
|
||||
$ make
|
||||
# make install
|
||||
```
|
||||
|
||||
# How To Use It
|
||||
```
|
||||
char *b32_encoded = base32_encode(unsigned char *input, size_t input_length, baseencode_error_t *err);
|
||||
|
||||
unsigned char *b32_decoded = base32_decode(char *input, size_t input_length, baseencode_error_t *err);
|
||||
|
||||
char *b64_encoded = base64_encode(unsigned char *input, size_t input_length, baseencode_error_t *err);
|
||||
|
||||
unsigned char *b64_decoded = base64_decode(char *input, size_t input_length, baseencode_error_t *err);
|
||||
```
|
||||
Please note that all the returned value **must be freed** once not needed any more.
|
||||
|
||||
## Errors
|
||||
In case of errors, `NULL` is returned and `err` is set to either one of:
|
||||
```
|
||||
INVALID_INPUT, EMPTY_STRING, INPUT_TOO_BIG, INVALID_B32_DATA, INVALID_B64_DATA, MEMORY_ALLOCATION,
|
||||
```
|
||||
otherwise, `err` is set to `SUCCESS`
|
||||
|
18
external/libbaseencode/SECURITY.md
vendored
Normal file
18
external/libbaseencode/SECURITY.md
vendored
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The following list describes whether a version is eligible or not for security updates.
|
||||
|
||||
| Version | Supported | EOL |
|
||||
| ------- | ------------------ |-------------|
|
||||
| 1.0.x | :heavy_check_mark: | - |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Should you find a vulnerability, please report it privately to me via [e-mail](mailto:paolostivanin@users.noreply.github.com).
|
||||
The following is the workflow:
|
||||
- security issue is found, an e-mail is sent to me
|
||||
- within 24 hours I will reply to your e-mail with some info like, for example, whether it actually is a security issue and how serious it is
|
||||
- within 7 days I will develop and ship a fix
|
||||
- once the update is out I will open a [security advisory](https://github.com/paolostivanin/OTPClient/security/advisories)
|
201
external/libbaseencode/src/base32.c
vendored
Normal file
201
external/libbaseencode/src/base32.c
vendored
Normal file
|
@ -0,0 +1,201 @@
|
|||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "common.h"
|
||||
|
||||
|
||||
static int is_valid_b32_input(const char *user_data, size_t data_len);
|
||||
|
||||
static int get_char_index(unsigned char c);
|
||||
|
||||
static const unsigned char b32_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567";
|
||||
|
||||
|
||||
// The encoding process represents 40-bit groups of input bits as output strings of 8 encoded characters. The input data must be null terminated.
|
||||
char *
|
||||
base32_encode(const unsigned char *user_data, size_t data_len, baseencode_error_t *err)
|
||||
{
|
||||
baseencode_error_t error;
|
||||
check_input(user_data, data_len, MAX_ENCODE_INPUT_LEN, &error);
|
||||
if (error != SUCCESS) {
|
||||
*err = error;
|
||||
if (error == EMPTY_STRING) {
|
||||
return strdup("");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t user_data_chars = 0, total_bits = 0;
|
||||
int num_of_equals = 0;
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
// As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required.
|
||||
// Check for null byte only at the end of the user given length, otherwise issue#23 may occur
|
||||
if (user_data[i] == '\0' && i == data_len-1) {
|
||||
break;
|
||||
} else {
|
||||
total_bits += 8;
|
||||
user_data_chars += 1;
|
||||
}
|
||||
}
|
||||
switch (total_bits % 40) {
|
||||
case 8:
|
||||
num_of_equals = 6;
|
||||
break;
|
||||
case 16:
|
||||
num_of_equals = 4;
|
||||
break;
|
||||
case 24:
|
||||
num_of_equals = 3;
|
||||
break;
|
||||
case 32:
|
||||
num_of_equals = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
size_t output_length = (user_data_chars * 8 + 4) / 5;
|
||||
char *encoded_data = calloc(output_length + num_of_equals + 1, 1);
|
||||
if (encoded_data == NULL) {
|
||||
*err = MEMORY_ALLOCATION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t first_octet, second_octet, third_octet, fourth_octet, fifth_octet;
|
||||
uint64_t quintuple;
|
||||
for (int i = 0, j = 0; i < user_data_chars;) {
|
||||
first_octet = i < user_data_chars ? user_data[i++] : 0;
|
||||
second_octet = i < user_data_chars ? user_data[i++] : 0;
|
||||
third_octet = i < user_data_chars ? user_data[i++] : 0;
|
||||
fourth_octet = i < user_data_chars ? user_data[i++] : 0;
|
||||
fifth_octet = i < user_data_chars ? user_data[i++] : 0;
|
||||
quintuple =
|
||||
((first_octet >> 3) << 35) +
|
||||
((((first_octet & 0x7) << 2) | (second_octet >> 6)) << 30) +
|
||||
(((second_octet & 0x3F) >> 1) << 25) +
|
||||
((((second_octet & 0x01) << 4) | (third_octet >> 4)) << 20) +
|
||||
((((third_octet & 0xF) << 1) | (fourth_octet >> 7)) << 15) +
|
||||
(((fourth_octet & 0x7F) >> 2) << 10) +
|
||||
((((fourth_octet & 0x3) << 3) | (fifth_octet >> 5)) << 5) +
|
||||
(fifth_octet & 0x1F);
|
||||
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 35) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 30) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 25) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 20) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 15) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 10) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 5) & 0x1F];
|
||||
encoded_data[j++] = b32_alphabet[(quintuple >> 0) & 0x1F];
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_of_equals; i++) {
|
||||
encoded_data[output_length + i] = '=';
|
||||
}
|
||||
encoded_data[output_length + num_of_equals] = '\0';
|
||||
|
||||
*err = SUCCESS;
|
||||
return encoded_data;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *
|
||||
base32_decode(const char *user_data_untrimmed, size_t data_len, baseencode_error_t *err)
|
||||
{
|
||||
baseencode_error_t error;
|
||||
check_input((unsigned char *)user_data_untrimmed, data_len, MAX_DECODE_BASE32_INPUT_LEN, &error);
|
||||
if (error != SUCCESS) {
|
||||
*err = error;
|
||||
if (error == EMPTY_STRING) {
|
||||
return (unsigned char *) strdup("");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *user_data = strdup(user_data_untrimmed);
|
||||
data_len -= strip_char(user_data, ' ');
|
||||
|
||||
if (!is_valid_b32_input(user_data, data_len)) {
|
||||
*err = INVALID_B32_DATA;
|
||||
free(user_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t user_data_chars = 0;
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
// As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required.
|
||||
if (user_data[i] != '=' && user_data[i] != '\0') {
|
||||
user_data_chars += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t output_length = (size_t) ((user_data_chars + 1.6 + 1) / 1.6); // round up
|
||||
unsigned char *decoded_data = calloc(output_length + 1, 1);
|
||||
if (decoded_data == NULL) {
|
||||
*err = MEMORY_ALLOCATION;
|
||||
free(user_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t mask = 0, current_byte = 0;
|
||||
int bits_left = 8;
|
||||
for (int i = 0, j = 0; i < user_data_chars; i++) {
|
||||
int char_index = get_char_index((unsigned char)user_data[i]);
|
||||
if (bits_left > BITS_PER_B32_BLOCK) {
|
||||
mask = (uint8_t) char_index << (bits_left - BITS_PER_B32_BLOCK);
|
||||
current_byte = (uint8_t) (current_byte | mask);
|
||||
bits_left -= BITS_PER_B32_BLOCK;
|
||||
} else {
|
||||
mask = (uint8_t) char_index >> (BITS_PER_B32_BLOCK - bits_left);
|
||||
current_byte = (uint8_t) (current_byte | mask);
|
||||
decoded_data[j++] = current_byte;
|
||||
current_byte = (uint8_t) (char_index << (BITS_PER_BYTE - BITS_PER_B32_BLOCK + bits_left));
|
||||
bits_left += BITS_PER_BYTE - BITS_PER_B32_BLOCK;
|
||||
}
|
||||
}
|
||||
decoded_data[output_length] = '\0';
|
||||
|
||||
free(user_data);
|
||||
|
||||
*err = SUCCESS;
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
is_valid_b32_input(const char *user_data, size_t data_len)
|
||||
{
|
||||
size_t found = 0, b32_alphabet_len = sizeof(b32_alphabet);
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
if (user_data[i] == '\0') {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
for(int j = 0; j < b32_alphabet_len; j++) {
|
||||
if(user_data[i] == b32_alphabet[j] || user_data[i] == '=') {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found != data_len) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_char_index(unsigned char c)
|
||||
{
|
||||
for (int i = 0; i < sizeof(b32_alphabet); i++) {
|
||||
if (b32_alphabet[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
174
external/libbaseencode/src/base64.c
vendored
Normal file
174
external/libbaseencode/src/base64.c
vendored
Normal file
|
@ -0,0 +1,174 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include "common.h"
|
||||
|
||||
static int is_valid_b64_input(const char *user_data, size_t data_len);
|
||||
|
||||
static int get_char_index(unsigned char c);
|
||||
|
||||
static const unsigned char b64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
|
||||
char *
|
||||
base64_encode(const unsigned char *user_data, size_t data_len, baseencode_error_t *err)
|
||||
{
|
||||
baseencode_error_t error;
|
||||
check_input(user_data, data_len, MAX_ENCODE_INPUT_LEN, &error);
|
||||
if (error != SUCCESS) {
|
||||
*err = error;
|
||||
if (error == EMPTY_STRING) {
|
||||
return strdup("");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
size_t user_data_chars = 0, total_bits = 0;
|
||||
int num_of_equals = 0;
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
// As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required.
|
||||
if (user_data[i] != '\0') {
|
||||
total_bits += 8;
|
||||
user_data_chars += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (total_bits % 24) {
|
||||
case 8:
|
||||
num_of_equals = 2;
|
||||
break;
|
||||
case 16:
|
||||
num_of_equals = 1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
size_t output_length = (user_data_chars * 8 + 4) / 6;
|
||||
char *encoded_data = calloc(output_length + num_of_equals + 1 + 3, 1);
|
||||
if (encoded_data == NULL) {
|
||||
*err = MEMORY_ALLOCATION;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t first_octet, second_octet, third_octet;
|
||||
for (int i = 0, j = 0, triple = 0; i < user_data_chars + 1;) {
|
||||
first_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0);
|
||||
second_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0);
|
||||
third_octet = (uint8_t) (i < user_data_chars+1 ? user_data[i++] : 0);
|
||||
triple = (first_octet << 0x10) + (second_octet << 0x08) + third_octet;
|
||||
|
||||
encoded_data[j++] = b64_alphabet[(triple >> 0x12) & 0x3F];
|
||||
encoded_data[j++] = b64_alphabet[(triple >> 0x0C) & 0x3F];
|
||||
encoded_data[j++] = b64_alphabet[(triple >> 0x06) & 0x3F];
|
||||
encoded_data[j++] = b64_alphabet[(triple >> 0x00) & 0x3F];
|
||||
}
|
||||
|
||||
for (int i = 0; i < num_of_equals; i++) {
|
||||
encoded_data[output_length + i] = '=';
|
||||
}
|
||||
encoded_data[output_length + num_of_equals] = '\0';
|
||||
|
||||
*err = SUCCESS;
|
||||
return encoded_data;
|
||||
}
|
||||
|
||||
|
||||
unsigned char *
|
||||
base64_decode(const char *user_data_untrimmed, size_t data_len, baseencode_error_t *err)
|
||||
{
|
||||
baseencode_error_t error;
|
||||
check_input((unsigned char *)user_data_untrimmed, data_len, MAX_DECODE_BASE64_INPUT_LEN, &error);
|
||||
if (error != SUCCESS) {
|
||||
*err = error;
|
||||
if (error == EMPTY_STRING) {
|
||||
return (unsigned char *) strdup("");
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
char *user_data = strdup(user_data_untrimmed);
|
||||
data_len -= strip_char(user_data, ' ');
|
||||
|
||||
if (!is_valid_b64_input(user_data, data_len)) {
|
||||
*err = INVALID_B64_DATA;
|
||||
free(user_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
size_t user_data_chars = 0;
|
||||
for (int z = 0; z < data_len; z++) {
|
||||
// As it's not known whether data_len is with or without the +1 for the null byte, a manual check is required.
|
||||
if (user_data[z] != '=' && user_data[z] != '\0') {
|
||||
user_data_chars += 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t output_length = data_len / 4 * 3;
|
||||
unsigned char *decoded_data = calloc(output_length + 1, 1);
|
||||
if (decoded_data == NULL) {
|
||||
*err = MEMORY_ALLOCATION;
|
||||
free(user_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint8_t mask = 0, current_byte = 0;
|
||||
int bits_left = 8;
|
||||
for (int i = 0, j = 0; i < user_data_chars; i++) {
|
||||
int char_index = get_char_index((unsigned char)user_data[i]);
|
||||
if (bits_left > BITS_PER_B64_BLOCK) {
|
||||
mask = (uint8_t) char_index << (bits_left - BITS_PER_B64_BLOCK);
|
||||
current_byte = (uint8_t) (current_byte | mask);
|
||||
bits_left -= BITS_PER_B64_BLOCK;
|
||||
} else {
|
||||
mask = (uint8_t) char_index >> (BITS_PER_B64_BLOCK - bits_left);
|
||||
current_byte = (uint8_t) (current_byte | mask);
|
||||
decoded_data[j++] = current_byte;
|
||||
current_byte = (uint8_t) (char_index << (BITS_PER_BYTE - BITS_PER_B64_BLOCK + bits_left));
|
||||
bits_left += BITS_PER_BYTE - BITS_PER_B64_BLOCK;
|
||||
}
|
||||
}
|
||||
decoded_data[output_length] = '\0';
|
||||
|
||||
free(user_data);
|
||||
|
||||
*err = SUCCESS;
|
||||
return decoded_data;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
is_valid_b64_input(const char *user_data, size_t data_len)
|
||||
{
|
||||
size_t found = 0, b64_alphabet_len = sizeof(b64_alphabet);
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
for(int j = 0; j < b64_alphabet_len; j++) {
|
||||
if(user_data[i] == b64_alphabet[j] || user_data[i] == '=') {
|
||||
found++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found != data_len) {
|
||||
return 0;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
get_char_index(unsigned char c)
|
||||
{
|
||||
for (int i = 0; i < sizeof(b64_alphabet); i++) {
|
||||
if (b64_alphabet[i] == c) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
28
external/libbaseencode/src/baseencode.h
vendored
Normal file
28
external/libbaseencode/src/baseencode.h
vendored
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
typedef enum _baseencode_errno {
|
||||
SUCCESS = 0,
|
||||
INVALID_INPUT = 1,
|
||||
EMPTY_STRING = 2,
|
||||
INPUT_TOO_BIG = 3,
|
||||
INVALID_B32_DATA = 4,
|
||||
INVALID_B64_DATA = 5,
|
||||
MEMORY_ALLOCATION = 6,
|
||||
} baseencode_error_t;
|
||||
|
||||
|
||||
char *base32_encode (const unsigned char *user_data,
|
||||
size_t data_len,
|
||||
baseencode_error_t *err);
|
||||
|
||||
unsigned char *base32_decode (const char *user_data,
|
||||
size_t data_len,
|
||||
baseencode_error_t *err);
|
||||
|
||||
char *base64_encode (const unsigned char *input_string,
|
||||
size_t input_length,
|
||||
baseencode_error_t *err);
|
||||
|
||||
unsigned char *base64_decode (const char *input_string,
|
||||
size_t input_length,
|
||||
baseencode_error_t *err);
|
50
external/libbaseencode/src/common.h
vendored
Normal file
50
external/libbaseencode/src/common.h
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "baseencode.h"
|
||||
|
||||
#define BITS_PER_BYTE 8
|
||||
#define BITS_PER_B32_BLOCK 5
|
||||
#define BITS_PER_B64_BLOCK 6
|
||||
|
||||
// 64 MB should be more than enough
|
||||
#define MAX_ENCODE_INPUT_LEN 64*1024*1024
|
||||
// if 64 MB of data is encoded than it should be also possible to decode it. That's why a bigger input is allowed for decoding
|
||||
#define MAX_DECODE_BASE32_INPUT_LEN ((MAX_ENCODE_INPUT_LEN * 8 + 4) / 5)
|
||||
#define MAX_DECODE_BASE64_INPUT_LEN ((MAX_ENCODE_INPUT_LEN * 8 + 4) / 6)
|
||||
|
||||
|
||||
static int
|
||||
strip_char(char *str, char strip)
|
||||
{
|
||||
int found = 0;
|
||||
char *p, *q;
|
||||
for (q = p = str; *p; p++) {
|
||||
if (*p != strip) {
|
||||
*q++ = *p;
|
||||
} else {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
*q = '\0';
|
||||
return found;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
check_input(const unsigned char *user_data, size_t data_len, int max_len, baseencode_error_t *err)
|
||||
{
|
||||
if (user_data == NULL || (data_len == 0 && user_data[0] != '\0')) {
|
||||
*err = INVALID_INPUT;
|
||||
return;
|
||||
} else if (user_data[0] == '\0') {
|
||||
*err = EMPTY_STRING;
|
||||
return;
|
||||
}
|
||||
|
||||
if (data_len > max_len) {
|
||||
*err = INPUT_TOO_BIG;
|
||||
return;
|
||||
}
|
||||
|
||||
*err = SUCCESS;
|
||||
}
|
36
external/libcotp/.gitignore
vendored
Normal file
36
external/libcotp/.gitignore
vendored
Normal file
|
@ -0,0 +1,36 @@
|
|||
.idea/
|
||||
cmake-build-debug/
|
||||
build/
|
||||
|
||||
# Object files
|
||||
*.o
|
||||
*.ko
|
||||
*.obj
|
||||
*.elf
|
||||
|
||||
# Precompiled Headers
|
||||
*.gch
|
||||
*.pch
|
||||
|
||||
# Libraries
|
||||
*.lib
|
||||
*.a
|
||||
*.la
|
||||
*.lo
|
||||
|
||||
# Shared objects (inc. Windows DLLs)
|
||||
*.dll
|
||||
*.so
|
||||
*.so.*
|
||||
*.dylib
|
||||
|
||||
# Executables
|
||||
*.exe
|
||||
*.out
|
||||
*.app
|
||||
*.i*86
|
||||
*.x86_64
|
||||
*.hex
|
||||
|
||||
# Debug files
|
||||
*.dSYM/
|
34
external/libcotp/CMakeLists.txt
vendored
Normal file
34
external/libcotp/CMakeLists.txt
vendored
Normal file
|
@ -0,0 +1,34 @@
|
|||
cmake_minimum_required(VERSION 3.5)
|
||||
project(cotp)
|
||||
|
||||
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(Gcrypt 1.6.0 REQUIRED)
|
||||
|
||||
include_directories(${GCRYPT_INCLUDE_DIR})
|
||||
|
||||
link_directories(${GCRYPT_LIBRARY_DIRS})
|
||||
|
||||
# set up versioning.
|
||||
set(BUILD_MAJOR "1")
|
||||
set(BUILD_MINOR "2")
|
||||
set(BUILD_VERSION "6")
|
||||
set(BUILD_VERSION ${BUILD_MAJOR}.${BUILD_MINOR}.${BUILD_VERSION})
|
||||
|
||||
set(CMAKE_C_STANDARD 11)
|
||||
|
||||
set(COTP_HEADERS src/cotp.h)
|
||||
set(SOURCE_FILES src/otp.c)
|
||||
|
||||
set(CMAKE_C_FLAGS "-Wall -Wextra -O3 -Wno-format-truncation -fstack-protector-strong -fPIC")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=3")
|
||||
|
||||
add_library(cotp SHARED ${SOURCE_FILES})
|
||||
|
||||
target_link_libraries(cotp ${GCRYPT_LIBRARIES} baseencode)
|
||||
target_include_directories(cotp PUBLIC src)
|
||||
|
||||
set_target_properties(cotp PROPERTIES VERSION ${BUILD_VERSION} SOVERSION ${BUILD_MAJOR}${BUILD_MINOR})
|
202
external/libcotp/LICENSE
vendored
Normal file
202
external/libcotp/LICENSE
vendored
Normal file
|
@ -0,0 +1,202 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "{}"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2018 Paolo Stivanin
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
61
external/libcotp/README.md
vendored
Normal file
61
external/libcotp/README.md
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
# libcotp
|
||||
<a href="https://scan.coverity.com/projects/paolostivanin-libcotp">
|
||||
<img alt="Coverity Scan Build Status"
|
||||
src="https://scan.coverity.com/projects/12748/badge.svg"/>
|
||||
</a>
|
||||
|
||||
C library that generates TOTP and HOTP according to [RFC-6238](https://tools.ietf.org/html/rfc6238)
|
||||
|
||||
## Requirements
|
||||
- [libbaseencode](https://github.com/paolostivanin/libbaseencode)
|
||||
- GCC/Clang and CMake to build the library
|
||||
- libgcrypt
|
||||
|
||||
## Build and Install
|
||||
```
|
||||
$ git clone https://github.com/paolostivanin/libcotp.git
|
||||
$ cd libcotp
|
||||
$ mkdir build && cd $_
|
||||
$ cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ../ # add -DBUILD_TESTING=ON if you want to compile also the tests
|
||||
$ make
|
||||
# make install
|
||||
```
|
||||
|
||||
## How To Use It
|
||||
```
|
||||
char *totp = get_totp (const char *base32_encoded_secret, int digits, int period, int algo, cotp_error_t *err);
|
||||
free (totp);
|
||||
|
||||
char *steam_totp = get_steam_totp (const char *secret, int period, cotp_error_t *err)
|
||||
|
||||
char *hotp = get_hotp (const char *base32_encoded_secret, long counter, int digits, int algo, cotp_error_t *err);
|
||||
free (hotp);
|
||||
|
||||
char *get_totp_at (const char *base32_encoded_secret, long target_date, int digits, int algo, cotp_error_t *err)
|
||||
|
||||
int is_valid = totp_verify (const har *base32_encoded_secret, const char *totp, int digits, int period, int algo, cotp_error_t *err);
|
||||
|
||||
int is_valid = hotp_verify (const char *base32_encoded_secret, long counter, digits, char *hotp, int algo, cotp_error_t *err);
|
||||
```
|
||||
|
||||
where:
|
||||
- `secret_key` is the **base32 encoded** secret. Usually, a website gives you the secret already base32 encoded, so you should pay attention to not encode the secret again.
|
||||
The format of the secret can either be `hxdm vjec jjws` or `HXDMVJECJJWS`. In the first case, the library will normalize the secret to second format before computing the OTP.
|
||||
- `digits` is between `3` and `10` inclusive
|
||||
- `period` is between `1` and `120` inclusive
|
||||
- `counter` is a value decided with the server
|
||||
- `target_date` is the target date specified as the unix epoch format in seconds
|
||||
- `algo` is either `SHA1`, `SHA256` or `SHA512`
|
||||
|
||||
## Errors
|
||||
`get_totp`, `get_hotp` and `get_totp_at` return `NULL` if an error occurs and `err` is set accordingly. The following errors are currently supported:
|
||||
- `GCRYPT_VERSION_MISMATCH`, set if the installed Gcrypt library is too old
|
||||
- `INVALID_B32_INPUT`, set if the given input is not valid base32 text
|
||||
- `INVALID_ALGO`, set if the given algo is not supported by the library
|
||||
- `INVALID_PERIOD`, set if `period` is `<= 0` or `> 120` seconds
|
||||
- `INVALID_DIGITS`, set if `digits` is `< 3` or `> 10`
|
||||
|
||||
`totp_verify` and `hotp_verify` can return, in addition to one of the previous code, also the error `INVALID_OTP` if the given OTP doesn't match the computed one.
|
||||
|
||||
In case of success, the value returned by `get_totp`, `get_hotp` and `get_totp_at` **must be freed** once no longer needed.
|
||||
|
20
external/libcotp/SECURITY.md
vendored
Normal file
20
external/libcotp/SECURITY.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
# Security Policy
|
||||
|
||||
## Supported Versions
|
||||
|
||||
The following list describes whether a version is eligible or not for security updates.
|
||||
|
||||
| Version | Supported | EOL |
|
||||
| ------- | ------------------ |-------------|
|
||||
| 1.2.x | :heavy_check_mark: | - |
|
||||
| 1.1.x | :x: | 31-Dec-2021 |
|
||||
| 1.0.x | :x: | 31-Dec-2021 |
|
||||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
Should you find a vulnerability, please report it privately to me via [e-mail](mailto:paolostivanin@users.noreply.github.com).
|
||||
The following is the workflow:
|
||||
- security issue is found, an e-mail is sent to me
|
||||
- within 24 hours I will reply to your e-mail with some info like, for example, whether it actually is a security issue and how serious it is
|
||||
- within 7 days I will develop and ship a fix
|
||||
- once the update is out I will open a [security advisory](https://github.com/paolostivanin/OTPClient/security/advisories)
|
31
external/libcotp/cmake/FindGcrypt.cmake
vendored
Normal file
31
external/libcotp/cmake/FindGcrypt.cmake
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
# Copyright (C) 2011 Felix Geyer <debfx@fobos.de>
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 2 or (at your option)
|
||||
# version 3 of the License.
|
||||
#
|
||||
# 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
find_path(GCRYPT_INCLUDE_DIR gcrypt.h)
|
||||
|
||||
find_library(GCRYPT_LIBRARIES gcrypt)
|
||||
|
||||
mark_as_advanced(GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIR)
|
||||
|
||||
if(GCRYPT_INCLUDE_DIR AND EXISTS "${GCRYPT_INCLUDE_DIR}/gcrypt.h")
|
||||
file(STRINGS "${GCRYPT_INCLUDE_DIR}/gcrypt.h" GCRYPT_H REGEX "^#define GCRYPT_VERSION \"[^\"]*\"$")
|
||||
string(REGEX REPLACE "^.*GCRYPT_VERSION \"([0-9]+).*$" "\\1" GCRYPT_VERSION_MAJOR "${GCRYPT_H}")
|
||||
string(REGEX REPLACE "^.*GCRYPT_VERSION \"[0-9]+\\.([0-9]+).*$" "\\1" GCRYPT_VERSION_MINOR "${GCRYPT_H}")
|
||||
string(REGEX REPLACE "^.*GCRYPT_VERSION \"[0-9]+\\.[0-9]+\\.([0-9]+).*$" "\\1" GCRYPT_VERSION_PATCH "${GCRYPT_H}")
|
||||
set(GCRYPT_VERSION_STRING "${GCRYPT_VERSION_MAJOR}.${GCRYPT_VERSION_MINOR}.${GCRYPT_VERSION_PATCH}")
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(Gcrypt DEFAULT_MSG GCRYPT_LIBRARIES GCRYPT_INCLUDE_DIR)
|
65
external/libcotp/src/cotp.h
vendored
Normal file
65
external/libcotp/src/cotp.h
vendored
Normal file
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
#include <gcrypt.h>
|
||||
|
||||
#define SHA1 GCRY_MD_SHA1
|
||||
#define SHA256 GCRY_MD_SHA256
|
||||
#define SHA512 GCRY_MD_SHA512
|
||||
|
||||
typedef enum _cotp_errno {
|
||||
VALID = 0,
|
||||
GCRYPT_VERSION_MISMATCH = 1,
|
||||
INVALID_B32_INPUT = 2,
|
||||
INVALID_ALGO = 3,
|
||||
INVALID_OTP = 4,
|
||||
INVALID_DIGITS = 5,
|
||||
INVALID_PERIOD = 6
|
||||
} cotp_error_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
char *get_hotp (const char *base32_encoded_secret,
|
||||
long counter,
|
||||
int digits,
|
||||
int sha_algo,
|
||||
cotp_error_t *err_code);
|
||||
|
||||
char *get_totp (const char *base32_encoded_secret,
|
||||
int digits,
|
||||
int period,
|
||||
int sha_algo,
|
||||
cotp_error_t *err_code);
|
||||
|
||||
char *get_steam_totp (const char *base32_encoded_secret,
|
||||
int period,
|
||||
cotp_error_t *err_code);
|
||||
|
||||
|
||||
char *get_totp_at (const char *base32_encoded_secret,
|
||||
long time,
|
||||
int digits,
|
||||
int period,
|
||||
int sha_algo,
|
||||
cotp_error_t *err_code);
|
||||
|
||||
char *get_steam_totp_at (const char *base32_encoded_secret,
|
||||
long timestamp,
|
||||
int period,
|
||||
cotp_error_t *err_code);
|
||||
|
||||
int totp_verify (const char *base32_encoded_secret,
|
||||
const char *user_totp,
|
||||
int digits,
|
||||
int period,
|
||||
int sha_algo);
|
||||
|
||||
int hotp_verify (const char *base32_encoded_secret,
|
||||
long counter,
|
||||
int digits,
|
||||
const char *user_hotp,
|
||||
int sha_algo);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
335
external/libcotp/src/otp.c
vendored
Normal file
335
external/libcotp/src/otp.c
vendored
Normal file
|
@ -0,0 +1,335 @@
|
|||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include <gcrypt.h>
|
||||
#include <baseencode.h>
|
||||
#include "cotp.h"
|
||||
|
||||
#define SHA1_DIGEST_SIZE 20
|
||||
#define SHA256_DIGEST_SIZE 32
|
||||
#define SHA512_DIGEST_SIZE 64
|
||||
|
||||
static long long int DIGITS_POWER[] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000, 10000000000};
|
||||
|
||||
|
||||
static int
|
||||
check_gcrypt()
|
||||
{
|
||||
if (!gcry_control(GCRYCTL_INITIALIZATION_FINISHED_P)) {
|
||||
if (!gcry_check_version("1.6.0")) {
|
||||
fprintf(stderr, "libgcrypt v1.6.0 and above is required\n");
|
||||
return -1;
|
||||
}
|
||||
gcry_control(GCRYCTL_DISABLE_SECMEM, 0);
|
||||
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
normalize_secret (const char *K)
|
||||
{
|
||||
char *nK = calloc (1, strlen (K) + 1);
|
||||
if (nK == NULL) {
|
||||
fprintf (stderr, "Error during memory allocation\n");
|
||||
return nK;
|
||||
}
|
||||
|
||||
int i = 0, j = 0;
|
||||
while (K[i] != '\0') {
|
||||
if (K[i] != ' ') {
|
||||
if (K[i] >= 'a' && K[i] <= 'z') {
|
||||
nK[j++] = (char) (K[i] - 32);
|
||||
} else {
|
||||
nK[j++] = K[i];
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return nK;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
get_steam_code(unsigned const char *hmac)
|
||||
{
|
||||
int offset = (hmac[SHA1_DIGEST_SIZE-1] & 0x0f);
|
||||
|
||||
// Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer
|
||||
int bin_code = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | ((hmac[offset + 3] & 0xff));
|
||||
|
||||
const char steam_alphabet[] = "23456789BCDFGHJKMNPQRTVWXY";
|
||||
|
||||
char code[6];
|
||||
size_t steam_alphabet_len = strlen(steam_alphabet);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int mod = bin_code % steam_alphabet_len;
|
||||
bin_code = bin_code / steam_alphabet_len;
|
||||
code[i] = steam_alphabet[mod];
|
||||
}
|
||||
code[5] = '\0';
|
||||
|
||||
return strdup(code);
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
truncate(unsigned const char *hmac, int digits_length, int algo)
|
||||
{
|
||||
// take the lower four bits of the last byte
|
||||
int offset = 0;
|
||||
switch (algo) {
|
||||
case SHA1:
|
||||
offset = (hmac[SHA1_DIGEST_SIZE-1] & 0x0f);
|
||||
break;
|
||||
case SHA256:
|
||||
offset = (hmac[SHA256_DIGEST_SIZE-1] & 0x0f);
|
||||
break;
|
||||
case SHA512:
|
||||
offset = (hmac[SHA512_DIGEST_SIZE-1] & 0x0f);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Starting from the offset, take the successive 4 bytes while stripping the topmost bit to prevent it being handled as a signed integer
|
||||
int bin_code = ((hmac[offset] & 0x7f) << 24) | ((hmac[offset + 1] & 0xff) << 16) | ((hmac[offset + 2] & 0xff) << 8) | ((hmac[offset + 3] & 0xff));
|
||||
|
||||
int token = bin_code % DIGITS_POWER[digits_length];
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
static unsigned char *
|
||||
compute_hmac(const char *K, long C, int algo)
|
||||
{
|
||||
baseencode_error_t err;
|
||||
size_t secret_len = (size_t) ((strlen(K) + 1.6 - 1) / 1.6);
|
||||
|
||||
char *normalized_K = normalize_secret (K);
|
||||
if (normalized_K == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
unsigned char *secret = base32_decode(normalized_K, strlen(normalized_K), &err);
|
||||
free (normalized_K);
|
||||
if (secret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char C_reverse_byte_order[8];
|
||||
int j, i;
|
||||
for (j = 0, i = 7; j < 8 && i >= 0; j++, i--)
|
||||
C_reverse_byte_order[i] = ((unsigned char *) &C)[j];
|
||||
|
||||
gcry_md_hd_t hd;
|
||||
gcry_md_open(&hd, algo, GCRY_MD_FLAG_HMAC);
|
||||
gcry_md_setkey(hd, secret, secret_len);
|
||||
gcry_md_write(hd, C_reverse_byte_order, sizeof(C_reverse_byte_order));
|
||||
gcry_md_final (hd);
|
||||
unsigned char *hmac = gcry_md_read(hd, algo);
|
||||
|
||||
free(secret);
|
||||
|
||||
return hmac;
|
||||
}
|
||||
|
||||
|
||||
static char *
|
||||
finalize(int digits_length, int tk)
|
||||
{
|
||||
char *token = malloc((size_t)digits_length + 1);
|
||||
if (token == NULL) {
|
||||
fprintf (stderr, "Error during memory allocation\n");
|
||||
return token;
|
||||
} else {
|
||||
int extra_char = digits_length < 10 ? 0 : 1;
|
||||
char *fmt = calloc(1, 5 + extra_char);
|
||||
if (fmt == NULL) {
|
||||
fprintf (stderr, "Error during memory allocation\n");
|
||||
free (token);
|
||||
return fmt;
|
||||
}
|
||||
memcpy (fmt, "%.", 3);
|
||||
snprintf (fmt + 2, 2 + extra_char, "%d", digits_length);
|
||||
memcpy (fmt + 3 + extra_char, "d", 2);
|
||||
snprintf (token, digits_length + 1, fmt, tk);
|
||||
free (fmt);
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_period(int period)
|
||||
{
|
||||
if (period <= 0 || period > 120) {
|
||||
return INVALID_PERIOD;
|
||||
}
|
||||
return VALID;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_otp_len(int digits_length)
|
||||
{
|
||||
if (digits_length < 3 || digits_length > 10) {
|
||||
return INVALID_DIGITS;
|
||||
}
|
||||
return VALID;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
check_algo(int algo)
|
||||
{
|
||||
if (algo != SHA1 && algo != SHA256 && algo != SHA512) {
|
||||
return INVALID_ALGO;
|
||||
} else {
|
||||
return VALID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_hotp(const char *secret, long timestamp, int digits, int algo, cotp_error_t *err_code)
|
||||
{
|
||||
if (check_gcrypt() == -1) {
|
||||
*err_code = GCRYPT_VERSION_MISMATCH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_algo(algo) == INVALID_ALGO) {
|
||||
*err_code = INVALID_ALGO;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_otp_len(digits) == INVALID_DIGITS) {
|
||||
*err_code = INVALID_DIGITS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
unsigned char *hmac = compute_hmac(secret, timestamp, algo);
|
||||
if (hmac == NULL) {
|
||||
*err_code = INVALID_B32_INPUT;
|
||||
return NULL;
|
||||
}
|
||||
int tk = truncate(hmac, digits, algo);
|
||||
char *token = finalize(digits, tk);
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_totp(const char *secret, int digits, int period, int algo, cotp_error_t *err_code)
|
||||
{
|
||||
return get_totp_at(secret, (long)time(NULL), digits, period, algo, err_code);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_steam_totp (const char *secret, int period, cotp_error_t *err_code)
|
||||
{
|
||||
// AFAIK, the secret is stored base64 encoded on the device. As I don't have time to waste on reverse engineering
|
||||
// this non-standard solution, the user is responsible for decoding the secret in whatever format this is and then
|
||||
// providing the library with the secret base32 encoded.
|
||||
return get_steam_totp_at (secret, (long)time(NULL), period, err_code);
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_totp_at(const char *secret, long current_timestamp, int digits, int period, int algo, cotp_error_t *err_code)
|
||||
{
|
||||
if (check_gcrypt() == -1) {
|
||||
*err_code = GCRYPT_VERSION_MISMATCH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_otp_len(digits) == INVALID_DIGITS) {
|
||||
*err_code = INVALID_DIGITS;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_period(period) == INVALID_PERIOD) {
|
||||
*err_code = INVALID_PERIOD;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long timestamp = current_timestamp / period;
|
||||
|
||||
cotp_error_t err;
|
||||
char *token = get_hotp(secret, timestamp, digits, algo, &err);
|
||||
if (token == NULL) {
|
||||
*err_code = err;
|
||||
return NULL;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
char *
|
||||
get_steam_totp_at (const char *secret, long current_timestamp, int period, cotp_error_t *err_code)
|
||||
{
|
||||
if (check_gcrypt() == -1) {
|
||||
*err_code = GCRYPT_VERSION_MISMATCH;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (check_period(period) == INVALID_PERIOD) {
|
||||
*err_code = INVALID_PERIOD;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
long timestamp = current_timestamp / period;
|
||||
|
||||
unsigned char *hmac = compute_hmac(secret, timestamp, SHA1);
|
||||
if (hmac == NULL) {
|
||||
*err_code = INVALID_B32_INPUT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return get_steam_code(hmac);
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
totp_verify(const char *secret, const char *user_totp, int digits, int period, int algo)
|
||||
{
|
||||
cotp_error_t err;
|
||||
char *current_totp = get_totp(secret, digits, period, algo, &err);
|
||||
if (current_totp == NULL) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int token_status;
|
||||
if (strcmp(current_totp, user_totp) != 0) {
|
||||
token_status = INVALID_OTP;
|
||||
} else {
|
||||
token_status = VALID;
|
||||
}
|
||||
free(current_totp);
|
||||
|
||||
return token_status;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
hotp_verify(const char *K, long C, int N, const char *user_hotp, int algo)
|
||||
{
|
||||
cotp_error_t err;
|
||||
char *current_hotp = get_hotp(K, C, N, algo, &err);
|
||||
if (current_hotp == NULL) {
|
||||
return err;
|
||||
}
|
||||
|
||||
int token_status;
|
||||
if (strcmp(current_hotp, user_hotp) != 0) {
|
||||
token_status = INVALID_OTP;
|
||||
} else {
|
||||
token_status = VALID;
|
||||
}
|
||||
free(current_hotp);
|
||||
|
||||
return token_status;
|
||||
}
|
|
@ -24,4 +24,6 @@ target_link_libraries(astra_desktop PUBLIC
|
|||
astra_core
|
||||
Qt5::Core
|
||||
Qt5::Widgets
|
||||
Qt5::Network)
|
||||
Qt5::Network
|
||||
cotp
|
||||
crypto)
|
|
@ -13,6 +13,7 @@
|
|||
#include <QSpinBox>
|
||||
#include <QToolTip>
|
||||
#include <keychain.h>
|
||||
#include <cotp.h>
|
||||
|
||||
#include "launchercore.h"
|
||||
#include "launcherwindow.h"
|
||||
|
@ -34,18 +35,18 @@ AutoLoginWindow::AutoLoginWindow(ProfileSettings& profile, LauncherCore& core, Q
|
|||
mainLayout->addWidget(cancelButton);
|
||||
|
||||
auto autologinTimer = new QTimer();
|
||||
connect(autologinTimer, &QTimer::timeout, [&] {
|
||||
qDebug() << "logging in!";
|
||||
|
||||
connect(autologinTimer, &QTimer::timeout, [&, this, autologinTimer] {
|
||||
// TODO: this is the second place where I have implemented this. this is a good idea to abstract, maybe? :-)
|
||||
auto loop = new QEventLoop();
|
||||
|
||||
QString username, password;
|
||||
QString otpSecret;
|
||||
|
||||
auto usernameJob = new QKeychain::ReadPasswordJob("LauncherWindow");
|
||||
usernameJob->setKey(profile.name + "-username");
|
||||
usernameJob->start();
|
||||
|
||||
core.connect(
|
||||
QObject::connect(
|
||||
usernameJob, &QKeychain::ReadPasswordJob::finished, [loop, usernameJob, &username](QKeychain::Job* j) {
|
||||
username = usernameJob->textData();
|
||||
loop->quit();
|
||||
|
@ -57,7 +58,7 @@ AutoLoginWindow::AutoLoginWindow(ProfileSettings& profile, LauncherCore& core, Q
|
|||
passwordJob->setKey(profile.name + "-password");
|
||||
passwordJob->start();
|
||||
|
||||
core.connect(
|
||||
QObject::connect(
|
||||
passwordJob, &QKeychain::ReadPasswordJob::finished, [loop, passwordJob, &password](QKeychain::Job* j) {
|
||||
password = passwordJob->textData();
|
||||
loop->quit();
|
||||
|
@ -65,16 +66,41 @@ AutoLoginWindow::AutoLoginWindow(ProfileSettings& profile, LauncherCore& core, Q
|
|||
|
||||
loop->exec();
|
||||
|
||||
// TODO: handle cases where the user doesn't want to store their OTP secret, so we have to manually prompt them
|
||||
if(profile.useOneTimePassword && profile.rememberOTPSecret) {
|
||||
auto otpJob = new QKeychain::ReadPasswordJob("LauncherWindow");
|
||||
otpJob->setKey(profile.name + "-otpsecret");
|
||||
otpJob->start();
|
||||
|
||||
QObject::connect(
|
||||
otpJob, &QKeychain::ReadPasswordJob::finished, [loop, otpJob, &otpSecret](QKeychain::Job* j) {
|
||||
otpSecret = otpJob->textData();
|
||||
loop->quit();
|
||||
});
|
||||
|
||||
loop->exec();
|
||||
}
|
||||
|
||||
auto info = new LoginInformation();
|
||||
info->settings = &profile;
|
||||
info->username = username;
|
||||
info->password = password;
|
||||
|
||||
if(profile.useOneTimePassword && profile.rememberOTPSecret) {
|
||||
// generate otp
|
||||
char *totp = get_totp (otpSecret.toStdString().c_str(), 6, 30, SHA1, nullptr);
|
||||
info->oneTimePassword = totp;
|
||||
free (totp);
|
||||
}
|
||||
|
||||
if (profile.isSapphire) {
|
||||
core.sapphireLauncher->login(profile.lobbyURL, *info);
|
||||
} else {
|
||||
core.squareBoot->bootCheck(*info);
|
||||
}
|
||||
|
||||
close();
|
||||
autologinTimer->stop();
|
||||
});
|
||||
connect(this, &AutoLoginWindow::loginCanceled, [autologinTimer] {
|
||||
autologinTimer->stop();
|
||||
|
|
|
@ -450,7 +450,7 @@ void SettingsWindow::setupLoginTab(QFormLayout& layout) {
|
|||
connect(otpSecretButton, &QPushButton::pressed, [=] {
|
||||
auto otpSecret = QInputDialog::getText(this, "OTP Input", "Enter your OTP Secret:");
|
||||
|
||||
auto job = new QKeychain::WritePasswordJob("SettingsWindow");
|
||||
auto job = new QKeychain::WritePasswordJob("LauncherWindow");
|
||||
job->setTextData(otpSecret);
|
||||
job->setKey(this->getCurrentProfile().name + "-otpsecret");
|
||||
job->start();
|
||||
|
|
Loading…
Add table
Reference in a new issue