mirror of
https://git.mirrors.martin98.com/https://github.com/prusa3d/PrusaSlicer.git
synced 2025-08-15 14:15:53 +08:00
Connect login: updating also user script when refreshed access token arives, this should fix passing old token on page reload
This commit is contained in:
parent
f9164da380
commit
3d130ceb76
@ -332,6 +332,8 @@ set(SLIC3R_GUI_SOURCES
|
|||||||
Utils/Http.hpp
|
Utils/Http.hpp
|
||||||
Utils/FixModelByWin10.cpp
|
Utils/FixModelByWin10.cpp
|
||||||
Utils/FixModelByWin10.hpp
|
Utils/FixModelByWin10.hpp
|
||||||
|
Utils/Jwt.cpp
|
||||||
|
Utils/Jwt.hpp
|
||||||
Utils/Moonraker.cpp
|
Utils/Moonraker.cpp
|
||||||
Utils/Moonraker.hpp
|
Utils/Moonraker.hpp
|
||||||
Utils/OctoPrint.cpp
|
Utils/OctoPrint.cpp
|
||||||
|
@ -475,8 +475,7 @@ void UserAccountCommunication::enqueue_refresh()
|
|||||||
BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in.";
|
BOOST_LOG_TRIVIAL(error) << "Connect Printers endpoint connection failed - Not Logged in.";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (m_session->is_enqueued(UserAccountActionID::USER_ACCOUNT_ACTION_REFRESH_TOKEN))
|
if (m_session->is_enqueued(UserAccountActionID::USER_ACCOUNT_ACTION_REFRESH_TOKEN)) {
|
||||||
{
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "User Account: Token refresh already enqueued, skipping...";
|
BOOST_LOG_TRIVIAL(debug) << "User Account: Token refresh already enqueued, skipping...";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#include "GUI_App.hpp"
|
#include "GUI_App.hpp"
|
||||||
#include "format.hpp"
|
#include "format.hpp"
|
||||||
#include "../Utils/Http.hpp"
|
#include "../Utils/Http.hpp"
|
||||||
|
#include "../Utils/Jwt.hpp"
|
||||||
#include "I18N.hpp"
|
#include "I18N.hpp"
|
||||||
|
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
@ -53,8 +54,17 @@ void UserActionGetWithEvent::perform(wxEvtHandler* evt_handler, const std::strin
|
|||||||
{
|
{
|
||||||
std::string url = m_url + input;
|
std::string url = m_url + input;
|
||||||
auto http = Http::get(std::move(url));
|
auto http = Http::get(std::move(url));
|
||||||
if (!access_token.empty())
|
if (!access_token.empty()) {
|
||||||
http.header("Authorization", "Bearer " + access_token);
|
http.header("Authorization", "Bearer " + access_token);
|
||||||
|
#ifndef _NDEBUG
|
||||||
|
// In debug mode, also verify the token expiration
|
||||||
|
// This is here to help with "dev" accounts with shorten (sort of faked) expiration time
|
||||||
|
// The /api/v1/me will accept these tokens even if these are fake-marked as expired
|
||||||
|
if (!Utils::verify_exp(access_token)) {
|
||||||
|
fail_callback("Token Expired");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
http.on_error([evt_handler, fail_callback, action_name = &m_action_name, fail_evt_type = m_fail_evt_type](std::string body, std::string error, unsigned status) {
|
http.on_error([evt_handler, fail_callback, action_name = &m_action_name, fail_evt_type = m_fail_evt_type](std::string body, std::string error, unsigned status) {
|
||||||
if (fail_callback)
|
if (fail_callback)
|
||||||
fail_callback(body);
|
fail_callback(body);
|
||||||
|
@ -540,7 +540,7 @@ void ConnectRequestHandler::handle_message(const std::string& message)
|
|||||||
|
|
||||||
void ConnectRequestHandler::on_connect_action_error(const std::string &message_data)
|
void ConnectRequestHandler::on_connect_action_error(const std::string &message_data)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(error) << "WebKit runtime error: " << message_data;
|
BOOST_LOG_TRIVIAL(error) << "WebView runtime error: " << message_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectRequestHandler::resend_config()
|
void ConnectRequestHandler::resend_config()
|
||||||
@ -550,7 +550,7 @@ void ConnectRequestHandler::resend_config()
|
|||||||
|
|
||||||
void ConnectRequestHandler::on_connect_action_log(const std::string& message_data)
|
void ConnectRequestHandler::on_connect_action_log(const std::string& message_data)
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(info) << "WebKit log: " << message_data;
|
BOOST_LOG_TRIVIAL(info) << "WebView log: " << message_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConnectRequestHandler::on_connect_action_request_config(const std::string& message_data)
|
void ConnectRequestHandler::on_connect_action_request_config(const std::string& message_data)
|
||||||
@ -647,8 +647,9 @@ wxString ConnectWebViewPanel::get_login_script(bool refresh)
|
|||||||
R"(
|
R"(
|
||||||
if (window._prusaSlicer_initLogin !== undefined) {
|
if (window._prusaSlicer_initLogin !== undefined) {
|
||||||
console.log('Refreshing login');
|
console.log('Refreshing login');
|
||||||
|
if (window._prusaSlicer !== undefined)
|
||||||
_prusaSlicer.postMessage({action: 'LOG', message: 'Refreshing login'});
|
_prusaSlicer.postMessage({action: 'LOG', message: 'Refreshing login'});
|
||||||
_prusaSlicer_initLogin('%s');
|
_prusaSlicer_initLogin('%s', 'refresh');
|
||||||
} else {
|
} else {
|
||||||
console.log('Refreshing login skipped as no _prusaSlicer_initLogin defined (yet?)');
|
console.log('Refreshing login skipped as no _prusaSlicer_initLogin defined (yet?)');
|
||||||
if (window._prusaSlicer === undefined) {
|
if (window._prusaSlicer === undefined) {
|
||||||
@ -660,7 +661,11 @@ wxString ConnectWebViewPanel::get_login_script(bool refresh)
|
|||||||
)"
|
)"
|
||||||
:
|
:
|
||||||
R"(
|
R"(
|
||||||
function _prusaSlicer_log(msg) { console.log(msg); _prusaSlicer.postMessage({action: 'LOG', message: msg}); }
|
function _prusaSlicer_log(msg) {
|
||||||
|
console.log(msg);
|
||||||
|
if (window._prusaSlicer !== undefined)
|
||||||
|
_prusaSlicer.postMessage({action: 'LOG', message: msg});
|
||||||
|
}
|
||||||
function _prusaSlicer_errorHandler(err) {
|
function _prusaSlicer_errorHandler(err) {
|
||||||
const msg = {
|
const msg = {
|
||||||
action: 'ERROR',
|
action: 'ERROR',
|
||||||
@ -677,7 +682,7 @@ wxString ConnectWebViewPanel::get_login_script(bool refresh)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _prusaSlicer_initLogin(token) {
|
async function _prusaSlicer_initLogin(token, reason) {
|
||||||
const parts = token.split('.');
|
const parts = token.split('.');
|
||||||
const claims = JSON.parse(atob(parts[1]));
|
const claims = JSON.parse(atob(parts[1]));
|
||||||
const now = new Date().getTime() / 1000;
|
const now = new Date().getTime() / 1000;
|
||||||
@ -694,10 +699,10 @@ wxString ConnectWebViewPanel::get_login_script(bool refresh)
|
|||||||
let error = false;
|
let error = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_prusaSlicer_log('Slicer Login request');
|
_prusaSlicer_log('Slicer Login request (' + reason + ') ' + token.substring(token.length - 8));
|
||||||
let resp = await fetch('/slicer/login', {method: 'POST', headers: {Authorization: 'Bearer ' + token}});
|
let resp = await fetch('/slicer/login', {method: 'POST', headers: {Authorization: 'Bearer ' + token}});
|
||||||
let body = await resp.text();
|
let body = await resp.text();
|
||||||
_prusaSlicer_log('Slicer Login resp ' + resp.status + ' body: ' + body);
|
_prusaSlicer_log('Slicer Login resp ' + resp.status + ' (' +reason + ' ' + token.substring(token.length - 8) + ') body: ' + body);
|
||||||
if (resp.status >= 500 || resp.status == 408) {
|
if (resp.status >= 500 || resp.status == 408) {
|
||||||
retry = true;
|
retry = true;
|
||||||
} else {
|
} else {
|
||||||
@ -721,7 +726,7 @@ wxString ConnectWebViewPanel::get_login_script(bool refresh)
|
|||||||
}
|
}
|
||||||
if (window._prusaSlicer_initialLoad === undefined) {
|
if (window._prusaSlicer_initialLoad === undefined) {
|
||||||
console.log('Initial login');
|
console.log('Initial login');
|
||||||
_prusaSlicer_initLogin('%s');
|
_prusaSlicer_initLogin('%s', 'init-load');
|
||||||
window._prusaSlicer_initialLoad = true;
|
window._prusaSlicer_initialLoad = true;
|
||||||
}
|
}
|
||||||
)",
|
)",
|
||||||
@ -743,7 +748,12 @@ void ConnectWebViewPanel::on_user_token(UserAccountSuccessEvent& e)
|
|||||||
e.Skip();
|
e.Skip();
|
||||||
auto access_token = wxGetApp().plater()->get_user_account()->get_access_token();
|
auto access_token = wxGetApp().plater()->get_user_account()->get_access_token();
|
||||||
assert(!access_token.empty());
|
assert(!access_token.empty());
|
||||||
wxString javascript = get_login_script(true);
|
wxString javascript = get_login_script(false);
|
||||||
|
|
||||||
|
m_browser->RemoveAllUserScripts();
|
||||||
|
m_browser->AddUserScript(javascript);
|
||||||
|
|
||||||
|
javascript = get_login_script(true);
|
||||||
//m_browser->AddUserScript(javascript, wxWEBVIEW_INJECT_AT_DOCUMENT_END);
|
//m_browser->AddUserScript(javascript, wxWEBVIEW_INJECT_AT_DOCUMENT_END);
|
||||||
BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript << "\n";
|
BOOST_LOG_TRIVIAL(debug) << "RunScript " << javascript << "\n";
|
||||||
m_browser->RunScriptAsync(javascript);
|
m_browser->RunScriptAsync(javascript);
|
||||||
|
58
src/slic3r/Utils/Jwt.cpp
Normal file
58
src/slic3r/Utils/Jwt.cpp
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "Jwt.hpp"
|
||||||
|
|
||||||
|
#include <ctime>
|
||||||
|
#include <sstream>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
#include <boost/beast/core/detail/base64.hpp>
|
||||||
|
#include <boost/property_tree/ptree.hpp>
|
||||||
|
#include <boost/property_tree/json_parser.hpp>
|
||||||
|
|
||||||
|
namespace Slic3r::Utils {
|
||||||
|
|
||||||
|
bool verify_exp(const std::string& token)
|
||||||
|
{
|
||||||
|
size_t payload_start = token.find('.');
|
||||||
|
if (payload_start == std::string::npos)
|
||||||
|
return false;
|
||||||
|
payload_start += 1; // payload starts after dot
|
||||||
|
|
||||||
|
const size_t payload_end = token.find('.', payload_start);
|
||||||
|
if (payload_end == std::string::npos)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
size_t encoded_length = payload_end - payload_start;
|
||||||
|
size_t decoded_length = boost::beast::detail::base64::decoded_size(encoded_length);
|
||||||
|
|
||||||
|
auto json_b64 = token.substr(payload_start, encoded_length);
|
||||||
|
std::replace(json_b64.begin(), json_b64.end(), '-', '+');
|
||||||
|
std::replace(json_b64.begin(), json_b64.end(), '_', '/');
|
||||||
|
|
||||||
|
size_t padding = encoded_length % 4;
|
||||||
|
encoded_length += padding;
|
||||||
|
while (padding--) json_b64 += '=';
|
||||||
|
|
||||||
|
|
||||||
|
std::string json;
|
||||||
|
json.resize(decoded_length + 2);
|
||||||
|
size_t read_bytes, written_bytes;
|
||||||
|
std::tie(written_bytes, read_bytes) = boost::beast::detail::base64::decode(json.data(), json_b64.data(), json_b64.length());
|
||||||
|
json.resize(written_bytes);
|
||||||
|
if (written_bytes == 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
namespace pt = boost::property_tree;
|
||||||
|
|
||||||
|
pt::ptree payload;
|
||||||
|
std::istringstream iss(json);
|
||||||
|
pt::json_parser::read_json(iss, payload);
|
||||||
|
|
||||||
|
auto exp_opt = payload.get_optional<double>("exp");
|
||||||
|
if (!exp_opt)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
auto now = time(nullptr);
|
||||||
|
return exp_opt.get() > now;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
10
src/slic3r/Utils/Jwt.hpp
Normal file
10
src/slic3r/Utils/Jwt.hpp
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
namespace Slic3r::Utils {
|
||||||
|
|
||||||
|
bool verify_exp(const std::string& token);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user