Я пытаюсь выполнить задачу, требующую создания пароля TOTP и отправки с ним запроса на публикацию с использованием аутентификации basi c. Если запрос будет выполнен успешно, я получу письмо с дальнейшими инструкциями. Я кодирую все в Node.js.
Я создал алгоритм TOTP, который я протестировал с результатами, полученными в спецификации rfc6238 (https://www.rfc-editor.org/rfc/rfc6238.txt), и все работает нормально, поэтому Сгенерированный TOTP должен быть в порядке.
Для вызова это часть инструкций:
Шаг TOTP X составляет 30 секунд. T0 равно 0. Используйте HMA C -SHA-512 для функции ha sh вместо HMA C -SHA-1 по умолчанию. Общий секретный ключ токена - это идентификатор пользователя, за которым следует строковое значение ASCII "CODE000000000000" (не включая двойные кавычки).
TOTP должен состоять из 10 цифр
ОШИБКА : Когда я отправляю запрос, я получаю ошибку 401, неавторизованную.
Я беспокоюсь, что в моем коде что-то упущено. Может быть, у меня в топоре ios пост-запрос? Пожалуйста, посмотрите и дайте мне знать. Я оставил свой тестовый код и таблицу rf c, чтобы вы тоже могли убедиться, что он работает.
const crypto = require("crypto");
// TOTP and HOTP use the same algorithm, the only difference
// is that the "count" param in TOTPs is time based
function generateTOTP(algorithm, secret, count, digits) {
// Convert the string to binary data in the form of a sequence of bytes
secret = Buffer.from(secret);
// Writes value to buf at the specified offset with the specified endianness
let countBuffer = Buffer.alloc(8, 0);
countBuffer.writeUInt32BE(count, 4);
// Creates and returns an Hmac object that uses the given algorithm and key
const hmac_result = crypto.createHmac(algorithm, secret)
.update(countBuffer)
.digest("hex");
// Chose the last byte of the hmac to do the dynamic truncation
const offset = parseInt(hmac_result.charAt(hmac_result.length - 1), 16);
// Dynamic truncation
let totp = parseInt(hmac_result.substr(offset * 2, 2 * 4), 16);
totp = totp & 0x7fffffff;
// Get only the digits needed
totp = totp % (10 ** digits);
// If there are not enough digits pad with 0
totp = totp.toString().padStart(digits, "0");
return totp;
}
// Date is a string. From where should calculate the unix epoch time
// in steps of 30 seconds
function getCount(date = new Date().toString()) {
const epoch = Math.round(new Date(date).getTime() / 1000.0);
return Math.floor(epoch / 30);
}
// Copied from: https://www.rfc-editor.org/rfc/rfc6238.txt
// PAGE 15
// I used this results to verify that my algorithm works properly, I also
// tested other dates but for this snippet I will leave only these 3.
// +-------------+--------------+------------------+----------+--------+
// | Time (sec) | UTC Time | Value of T (hex) | TOTP | Mode |
// +-------------+--------------+------------------+----------+--------+
// | 1111111109 | 2005-03-18 | 00000000023523EC | 07081804 | SHA1 |
// | | 01:58:29 | | | |
// | 1111111109 | 2005-03-18 | 00000000023523EC | 68084774 | SHA256 |
// | | 01:58:29 | | | |
// | 1111111109 | 2005-03-18 | 00000000023523EC | 25091201 | SHA512 |
// | | 01:58:29 | | | |
// +-------------+--------------+------------------+----------+--------+
// All of these tests succeed, the TOTP matches the one in the table
let time = getCount("2005-03-18 01:58:29 UTC");
let secret = "12345678901234567890";
let totp = generateTOTP("sha1", secret, time, 8);
console.log("sha1 ", totp, "should be 07081804");
// To create a TOTP password with sha256 and sha512 the secret length must
// be 32 for sha256 and 64 for sha512.
// Look up the errata of 6238 for more (https://www.rfc-editor.org/errata/eid5132)
secret = "12345678901234567890";
secret = secret + secret;
secret = secret.substr(0, 32);
totp = generateTOTP("sha256", secret, time, 8)
console.log("sha256", totp, "should be 68084774");
secret = "12345678901234567890";
secret = secret + secret + secret + secret;
secret = secret.substr(0, 64);
totp = generateTOTP("sha512", secret, time, 8)
console.log("sha512", totp, "should be 25091201");
// This is the code for my post request
const axios = require("axios");
// The secret is set up as follows
secret = "name.surname@email.comCODE000000000000";
secret = secret + secret + secret + secret;
secret = secret.substr(0, 64);
// To generate the real TOTP, get the unix epoch time
time = Math.round(Date.now() / 1000);
// Matches the unix epoch clock https://www.epochconverter.com/clock
console.log(time);
// Ge the steps in T = 30
time = Math.floor(time / 30);
totp = generateTOTP("sha512", secret, time, 10)
console.log(totp);
// The contact_email field is also the username used in the auth
const data = {
"github_url": "https://github.com/user/repo",
"contact_email": "name.surname@email.com"
}
const username = "name.surname@email.com";
const credentials = Buffer.from(`${username}:${totp}`, "utf8").toString("base64")
console.log(credentials);
// I keep getting 401 unauthorized
axios
.post("https://api.something/hello", {
data: data,
// Not sure if withCredentials should be used, I tried removing it but no difference
withCredentials: true,
headers: {
"Authorization": `Basic ${credentials}`,
"Accept": "*/*",
"Content-Type": "application/json"
}
})
.then(res => console.log(res))
.catch(err => console.log(err.message));