UI: Add Whats New for macOS/Linux
- Requires MbedTLS on Linux - Enabled by default on macOS and Flatpak - Enabled on linux via ENABLE_WHATSNEW_LINUX - Enables compilation of blake2 on Linux/macOS - Makes header name check also work with lowercase header - Changes WahtsNew to be only enabled when browser panels are availablemaster
parent
9216a62edc
commit
9140c260ee
|
@ -311,6 +311,18 @@ if(TARGET OBS::browser-panels)
|
||||||
if(RESTREAM_ENABLED)
|
if(RESTREAM_ENABLED)
|
||||||
target_sources(obs PRIVATE auth-restream.cpp auth-restream.hpp)
|
target_sources(obs PRIVATE auth-restream.cpp auth-restream.hpp)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(OS_WINDOWS OR OS_MACOS)
|
||||||
|
set(ENABLE_WHATSNEW
|
||||||
|
ON
|
||||||
|
CACHE INTERNAL "Enable WhatsNew dialog")
|
||||||
|
elseif(OS_LINUX)
|
||||||
|
option(ENABLE_WHATSNEW "Enable WhatsNew dialog" ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ENABLE_WHATSNEW)
|
||||||
|
target_compile_definitions(obs PRIVATE WHATSNEW_ENABLED)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(YOUTUBE_ENABLED)
|
if(YOUTUBE_ENABLED)
|
||||||
|
@ -427,6 +439,21 @@ elseif(OS_MACOS)
|
||||||
target_sources(obs PRIVATE forms/OBSPermissions.ui window-permissions.cpp
|
target_sources(obs PRIVATE forms/OBSPermissions.ui window-permissions.cpp
|
||||||
window-permissions.hpp)
|
window-permissions.hpp)
|
||||||
|
|
||||||
|
if(ENABLE_WHATSNEW)
|
||||||
|
find_library(SECURITY Security)
|
||||||
|
mark_as_advanced(SECURITY)
|
||||||
|
target_link_libraries(obs PRIVATE ${SECURITY} OBS::blake2)
|
||||||
|
|
||||||
|
target_sources(
|
||||||
|
obs
|
||||||
|
PRIVATE nix-update/crypto-helpers.hpp
|
||||||
|
nix-update/crypto-helpers-mac.mm
|
||||||
|
nix-update/nix-update.cpp
|
||||||
|
nix-update/nix-update.hpp
|
||||||
|
nix-update/nix-update-helpers.cpp
|
||||||
|
nix-update/nix-update-helpers.hpp)
|
||||||
|
endif()
|
||||||
|
|
||||||
set_source_files_properties(platform-osx.mm PROPERTIES COMPILE_FLAGS
|
set_source_files_properties(platform-osx.mm PROPERTIES COMPILE_FLAGS
|
||||||
-fobjc-arc)
|
-fobjc-arc)
|
||||||
|
|
||||||
|
@ -447,6 +474,25 @@ elseif(OS_POSIX)
|
||||||
if(OS_FREEBSD)
|
if(OS_FREEBSD)
|
||||||
target_link_libraries(obs PRIVATE procstat)
|
target_link_libraries(obs PRIVATE procstat)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(OS_LINUX AND ENABLE_WHATSNEW)
|
||||||
|
find_package(MbedTLS)
|
||||||
|
if(NOT MBEDTLS_FOUND)
|
||||||
|
obs_status(
|
||||||
|
FATAL_ERROR
|
||||||
|
"mbedTLS not found, but required for WhatsNew support on Linux")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
target_sources(
|
||||||
|
obs
|
||||||
|
PRIVATE nix-update/crypto-helpers.hpp
|
||||||
|
nix-update/crypto-helpers-mbedtls.cpp
|
||||||
|
nix-update/nix-update.cpp
|
||||||
|
nix-update/nix-update.hpp
|
||||||
|
nix-update/nix-update-helpers.cpp
|
||||||
|
nix-update/nix-update-helpers.hpp)
|
||||||
|
target_link_libraries(obs PRIVATE Mbedtls::Mbedtls OBS::blake2)
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
get_target_property(_SOURCES obs SOURCES)
|
get_target_property(_SOURCES obs SOURCES)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAl3sverw9HQ+rYQNn9Ca7
|
||||||
|
9LU62nG6NozE/FsIVNer+W/hueE8WQ1mrFP+2yA+iYRutYPeEgpxtodHhgkR4pEK
|
||||||
|
Vnrr18q4szlv89QI7t8lMoLTlF+t1IR0V4wJV34I3C+359KixnzL0Bl9aj/zDcrX
|
||||||
|
Wl5pHTioJwYOgMiBGLyPeitMFdjjTIpCM+mxTWXCrZ9dPUKvZtgzjd+IzlHidHtO
|
||||||
|
ORBN5mRs8LNO58k79r77DcgQYPNiiCtWgC+Y4K7uSZX3Hveom2tHbVXy0L/Cl7fM
|
||||||
|
HKqfcQGuyrvud42OrWarAsn2p2Ei6Kzxb3G6ESCw15nHAgLal8zSq7+raE/xkLpC
|
||||||
|
bYg5gmY6vbmWnq9dqWrUzaqOfrZPgvgG0WvkBShfaEOBaIUxA3QBgzAZhqeedF9h
|
||||||
|
afMGMM9qVbfwuuzJ2uh+InaGaeH2c04oVcDFfeOaDuxRjCCbqr5sLSo1CWokynjN
|
||||||
|
CB+b2rQF7DPPbD4s/nT9Nsck/NFzrBXRO+dqkeBwDUCv7bZgW7OxuOX07LTqfp5s
|
||||||
|
OeGgububiwY3UdHYq+L9JqISG1tM4HeKjaHju1MDjvHZ2DbmLwUxuYa6JZDKWs7r
|
||||||
|
IrdDwx3JwacF66h3YUW6tzUZhztcmQepP/u7BgGrkOPPpYA0NEJ80SeAx7hiN4va
|
||||||
|
eEQKnRn+EpBN6UBa5f7LoK8CAwEAAQ==
|
||||||
|
-----END PUBLIC KEY-----
|
|
@ -0,0 +1,32 @@
|
||||||
|
#include "crypto-helpers.hpp"
|
||||||
|
|
||||||
|
#import <Foundation/Foundation.h>
|
||||||
|
#import <Security/Security.h>
|
||||||
|
#import <Security/SecKey.h>
|
||||||
|
|
||||||
|
bool VerifySignature(const uint8_t *pubKey, const size_t pubKeyLen,
|
||||||
|
const uint8_t *buf, const size_t len, const uint8_t *sig,
|
||||||
|
const size_t sigLen)
|
||||||
|
{
|
||||||
|
NSData *pubKeyData = [NSData dataWithBytes:pubKey length:pubKeyLen];
|
||||||
|
CFArrayRef items = nullptr;
|
||||||
|
|
||||||
|
OSStatus res = SecItemImport((CFDataRef)pubKeyData, nullptr, nullptr,
|
||||||
|
nullptr, (SecItemImportExportFlags)0,
|
||||||
|
nullptr, nullptr, &items);
|
||||||
|
if (res != errSecSuccess)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
SecKeyRef pubKeyRef = (SecKeyRef)CFArrayGetValueAtIndex(items, 0);
|
||||||
|
NSData *signedData = [NSData dataWithBytes:buf length:len];
|
||||||
|
NSData *signature = [NSData dataWithBytes:sig length:sigLen];
|
||||||
|
|
||||||
|
CFErrorRef errRef;
|
||||||
|
bool result = SecKeyVerifySignature(
|
||||||
|
pubKeyRef, kSecKeyAlgorithmRSASignatureMessagePKCS1v15SHA512,
|
||||||
|
(__bridge CFDataRef)signedData, (__bridge CFDataRef)signature,
|
||||||
|
&errRef);
|
||||||
|
|
||||||
|
CFRelease(items);
|
||||||
|
return result;
|
||||||
|
};
|
|
@ -0,0 +1,39 @@
|
||||||
|
#include "crypto-helpers.hpp"
|
||||||
|
|
||||||
|
#include "mbedtls/md.h"
|
||||||
|
#include "mbedtls/pk.h"
|
||||||
|
|
||||||
|
bool VerifySignature(const uint8_t *pubKey, const size_t pubKeyLen,
|
||||||
|
const uint8_t *buf, const size_t len, const uint8_t *sig,
|
||||||
|
const size_t sigLen)
|
||||||
|
{
|
||||||
|
bool result = false;
|
||||||
|
int ret = 1;
|
||||||
|
unsigned char hash[64];
|
||||||
|
mbedtls_pk_context pk;
|
||||||
|
|
||||||
|
mbedtls_pk_init(&pk);
|
||||||
|
|
||||||
|
// Parse PEM key
|
||||||
|
if ((ret = mbedtls_pk_parse_public_key(&pk, pubKey, pubKeyLen + 1)) !=
|
||||||
|
0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// Hash input buffer
|
||||||
|
if ((ret = mbedtls_md(mbedtls_md_info_from_type(MBEDTLS_MD_SHA512), buf,
|
||||||
|
len, hash)) != 0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
// Verify signautre
|
||||||
|
if ((ret = mbedtls_pk_verify(&pk, MBEDTLS_MD_SHA512, hash, 64, sig,
|
||||||
|
sigLen)) != 0) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
exit:
|
||||||
|
mbedtls_pk_free(&pk);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
bool VerifySignature(const uint8_t *pubKey, const size_t pubKeyLen,
|
||||||
|
const uint8_t *buf, const size_t len, const uint8_t *sig,
|
||||||
|
const size_t sigLen);
|
|
@ -0,0 +1,27 @@
|
||||||
|
#include "nix-update-helpers.hpp"
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
std::string vstrprintf(const char *format, va_list args)
|
||||||
|
{
|
||||||
|
if (!format)
|
||||||
|
return std::string();
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
int size = (int)vsnprintf(nullptr, 0, format, args) + 1;
|
||||||
|
str.resize(size);
|
||||||
|
vsnprintf(&str[0], size, format, args);
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string strprintf(const char *format, ...)
|
||||||
|
{
|
||||||
|
std::string str;
|
||||||
|
va_list args;
|
||||||
|
|
||||||
|
va_start(args, format);
|
||||||
|
str = vstrprintf(format, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return str;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
std::string strprintf(const char *format, ...);
|
|
@ -0,0 +1,282 @@
|
||||||
|
#include "nix-update.hpp"
|
||||||
|
#include "crypto-helpers.hpp"
|
||||||
|
#include "nix-update-helpers.hpp"
|
||||||
|
#include "obs-app.hpp"
|
||||||
|
#include "remote-text.hpp"
|
||||||
|
#include "platform.hpp"
|
||||||
|
|
||||||
|
#include <util/util.hpp>
|
||||||
|
#include <blake2.h>
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
|
#include <QRandomGenerator>
|
||||||
|
#include <QByteArray>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
#include <browser-panel.hpp>
|
||||||
|
|
||||||
|
struct QCef;
|
||||||
|
extern QCef *cef;
|
||||||
|
|
||||||
|
#ifndef MAC_WHATSNEW_URL
|
||||||
|
#define MAC_WHATSNEW_URL "https://obsproject.com/update_studio/whatsnew.json"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef LINUX_WHATSNEW_URL
|
||||||
|
#define LINUX_WHATSNEW_URL "https://obsproject.com/update_studio/whatsnew.json"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __APPLE__
|
||||||
|
#define WHATSNEW_URL MAC_WHATSNEW_URL
|
||||||
|
#else
|
||||||
|
#define WHATSNEW_URL LINUX_WHATSNEW_URL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HASH_READ_BUF_SIZE 65536
|
||||||
|
#define BLAKE2_HASH_LENGTH 20
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static bool QuickWriteFile(const char *file, std::string &data)
|
||||||
|
try {
|
||||||
|
std::ofstream fileStream(file, std::ios::binary);
|
||||||
|
if (fileStream.fail())
|
||||||
|
throw strprintf("Failed to open file '%s': %s", file,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
fileStream.write(data.data(), data.size());
|
||||||
|
if (fileStream.fail())
|
||||||
|
throw strprintf("Failed to write file '%s': %s", file,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (std::string &text) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool QuickReadFile(const char *file, std::string &data)
|
||||||
|
try {
|
||||||
|
std::ifstream fileStream(file);
|
||||||
|
if (!fileStream.is_open() || fileStream.fail())
|
||||||
|
throw strprintf("Failed to open file '%s': %s", file,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
fileStream.seekg(0, fileStream.end);
|
||||||
|
size_t size = fileStream.tellg();
|
||||||
|
fileStream.seekg(0);
|
||||||
|
|
||||||
|
data.resize(size);
|
||||||
|
fileStream.read(&data[0], size);
|
||||||
|
|
||||||
|
if (fileStream.fail())
|
||||||
|
throw strprintf("Failed to write file '%s': %s", file,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (std::string &text) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CalculateFileHash(const char *path, uint8_t *hash)
|
||||||
|
try {
|
||||||
|
blake2b_state blake2;
|
||||||
|
if (blake2b_init(&blake2, BLAKE2_HASH_LENGTH) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
std::ifstream file(path, std::ios::binary);
|
||||||
|
if (!file.is_open() || file.fail())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
char buf[HASH_READ_BUF_SIZE];
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
file.read(buf, HASH_READ_BUF_SIZE);
|
||||||
|
size_t read = file.gcount();
|
||||||
|
if (blake2b_update(&blake2, &buf, read) != 0)
|
||||||
|
return false;
|
||||||
|
if (file.eof())
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (blake2b_final(&blake2, hash, BLAKE2_HASH_LENGTH) != 0)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (std::string &text) {
|
||||||
|
blog(LOG_DEBUG, "%s: %s", __FUNCTION__, text.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
void GenerateGUID(std::string &guid)
|
||||||
|
{
|
||||||
|
const char alphabet[] = "0123456789abcdef";
|
||||||
|
QRandomGenerator *rng = QRandomGenerator::system();
|
||||||
|
|
||||||
|
guid.resize(40);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < 40; i++) {
|
||||||
|
guid[i] = alphabet[rng->bounded(0, 16)];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GetProgramGUID()
|
||||||
|
{
|
||||||
|
static std::mutex m;
|
||||||
|
std::lock_guard<std::mutex> lock(m);
|
||||||
|
|
||||||
|
/* NOTE: this is an arbitrary random number that we use to count the
|
||||||
|
* number of unique OBS installations and is not associated with any
|
||||||
|
* kind of identifiable information */
|
||||||
|
const char *pguid =
|
||||||
|
config_get_string(GetGlobalConfig(), "General", "InstallGUID");
|
||||||
|
std::string guid;
|
||||||
|
if (pguid)
|
||||||
|
guid = pguid;
|
||||||
|
|
||||||
|
if (guid.empty()) {
|
||||||
|
GenerateGUID(guid);
|
||||||
|
|
||||||
|
if (!guid.empty())
|
||||||
|
config_set_string(GetGlobalConfig(), "General",
|
||||||
|
"InstallGUID", guid.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
return guid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
static void LoadPublicKey(std::string &pubkey)
|
||||||
|
{
|
||||||
|
std::string pemFilePath;
|
||||||
|
|
||||||
|
if (!GetDataFilePath("OBSPublicRSAKey.pem", pemFilePath))
|
||||||
|
throw std::string("Could not find OBS public key file!");
|
||||||
|
if (!QuickReadFile(pemFilePath.c_str(), pubkey))
|
||||||
|
throw std::string("Could not read OBS public key file!");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool CheckDataSignature(const char *name, const std::string &data,
|
||||||
|
const std::string &hexSig)
|
||||||
|
try {
|
||||||
|
if (hexSig.empty() || hexSig.length() > 0xFFFF ||
|
||||||
|
(hexSig.length() & 1) != 0)
|
||||||
|
throw strprintf("Missing or invalid signature for %s: %s", name,
|
||||||
|
hexSig.c_str());
|
||||||
|
|
||||||
|
static std::string obsPubKey;
|
||||||
|
if (obsPubKey.empty())
|
||||||
|
LoadPublicKey(obsPubKey);
|
||||||
|
|
||||||
|
// Convert hex string to bytes
|
||||||
|
auto signature = QByteArray::fromHex(hexSig.data());
|
||||||
|
|
||||||
|
if (!VerifySignature((uint8_t *)obsPubKey.data(), obsPubKey.size(),
|
||||||
|
(uint8_t *)data.data(), data.size(),
|
||||||
|
(uint8_t *)signature.data(), signature.size()))
|
||||||
|
throw strprintf("Signature check failed for %s", name);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
|
||||||
|
} catch (std::string &text) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
void WhatsNewInfoThread::run()
|
||||||
|
try {
|
||||||
|
long responseCode;
|
||||||
|
std::vector<std::string> extraHeaders;
|
||||||
|
std::string text;
|
||||||
|
std::string error;
|
||||||
|
std::string signature;
|
||||||
|
uint8_t whatsnewHash[BLAKE2_HASH_LENGTH];
|
||||||
|
bool success;
|
||||||
|
|
||||||
|
BPtr<char> whatsnewPath =
|
||||||
|
GetConfigPathPtr("obs-studio/updates/whatsnew.json");
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* avoid downloading json again */
|
||||||
|
|
||||||
|
if (CalculateFileHash(whatsnewPath, whatsnewHash)) {
|
||||||
|
auto hash = QByteArray::fromRawData((const char *)whatsnewHash,
|
||||||
|
BLAKE2_HASH_LENGTH);
|
||||||
|
|
||||||
|
QString header = "If-None-Match: " + hash.toHex();
|
||||||
|
extraHeaders.push_back(move(header.toStdString()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* get current install GUID */
|
||||||
|
|
||||||
|
std::string guid = GetProgramGUID();
|
||||||
|
|
||||||
|
if (!guid.empty()) {
|
||||||
|
std::string header = "X-OBS2-GUID: " + guid;
|
||||||
|
extraHeaders.push_back(move(header));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* get json from server */
|
||||||
|
|
||||||
|
success = GetRemoteFile(WHATSNEW_URL, text, error, &responseCode,
|
||||||
|
nullptr, "", nullptr, extraHeaders, &signature);
|
||||||
|
|
||||||
|
if (!success || (responseCode != 200 && responseCode != 304)) {
|
||||||
|
if (responseCode == 404)
|
||||||
|
return;
|
||||||
|
|
||||||
|
throw strprintf("Failed to fetch whatsnew file: %s",
|
||||||
|
error.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* verify file signature */
|
||||||
|
|
||||||
|
if (responseCode == 200) {
|
||||||
|
success = CheckDataSignature("whatsnew", text, signature);
|
||||||
|
if (!success)
|
||||||
|
throw std::string("Invalid whatsnew signature");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* write or load json */
|
||||||
|
|
||||||
|
if (responseCode == 200) {
|
||||||
|
if (!QuickWriteFile(whatsnewPath, text))
|
||||||
|
throw strprintf("Could not write file '%s'",
|
||||||
|
whatsnewPath.Get());
|
||||||
|
} else {
|
||||||
|
if (!QuickReadFile(whatsnewPath, text))
|
||||||
|
throw strprintf("Could not read file '%s'",
|
||||||
|
whatsnewPath.Get());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------- *
|
||||||
|
* success */
|
||||||
|
|
||||||
|
emit Result(QString::fromStdString(text));
|
||||||
|
|
||||||
|
} catch (std::string &text) {
|
||||||
|
blog(LOG_WARNING, "%s: %s", __FUNCTION__, text.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
void WhatsNewBrowserInitThread::run()
|
||||||
|
{
|
||||||
|
cef->wait_for_browser_init();
|
||||||
|
emit Result(url);
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QThread>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
class WhatsNewInfoThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
virtual void run() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void Result(const QString &text);
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline WhatsNewInfoThread() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WhatsNewBrowserInitThread : public QThread {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
QString url;
|
||||||
|
|
||||||
|
virtual void run() override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void Result(const QString &url);
|
||||||
|
|
||||||
|
public:
|
||||||
|
inline WhatsNewBrowserInitThread(const QString &url_) : url(url_) {}
|
||||||
|
};
|
|
@ -551,7 +551,9 @@ static bool MakeUserDirs()
|
||||||
return false;
|
return false;
|
||||||
if (!do_mkdir(path))
|
if (!do_mkdir(path))
|
||||||
return false;
|
return false;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef WHATSNEW_ENABLED
|
||||||
if (GetConfigPath(path, sizeof(path), "obs-studio/updates") <= 0)
|
if (GetConfigPath(path, sizeof(path), "obs-studio/updates") <= 0)
|
||||||
return false;
|
return false;
|
||||||
if (!do_mkdir(path))
|
if (!do_mkdir(path))
|
||||||
|
|
|
@ -208,7 +208,9 @@ bool GetRemoteFile(const char *url, std::string &str, std::string &error,
|
||||||
} else if (signature) {
|
} else if (signature) {
|
||||||
for (string &h : header_in_list) {
|
for (string &h : header_in_list) {
|
||||||
string name = h.substr(0, 13);
|
string name = h.substr(0, 13);
|
||||||
if (name == "X-Signature: ") {
|
// HTTP headers are technically case-insensitive
|
||||||
|
if (name == "X-Signature: " ||
|
||||||
|
name == "x-signature: ") {
|
||||||
*signature = h.substr(13);
|
*signature = h.substr(13);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,6 +81,10 @@
|
||||||
#include "windows.h"
|
#include "windows.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && defined(WHATSNEW_ENABLED)
|
||||||
|
#include "nix-update/nix-update.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ui_OBSBasic.h"
|
#include "ui_OBSBasic.h"
|
||||||
#include "ui_ColorSelect.h"
|
#include "ui_ColorSelect.h"
|
||||||
|
|
||||||
|
@ -2106,7 +2110,7 @@ void OBSBasic::OnFirstLoad()
|
||||||
if (api)
|
if (api)
|
||||||
api->on_event(OBS_FRONTEND_EVENT_FINISHED_LOADING);
|
api->on_event(OBS_FRONTEND_EVENT_FINISHED_LOADING);
|
||||||
|
|
||||||
#if defined(BROWSER_AVAILABLE) && defined(_WIN32)
|
#ifdef WHATSNEW_ENABLED
|
||||||
/* Attempt to load init screen if available */
|
/* Attempt to load init screen if available */
|
||||||
if (cef) {
|
if (cef) {
|
||||||
WhatsNewInfoThread *wnit = new WhatsNewInfoThread();
|
WhatsNewInfoThread *wnit = new WhatsNewInfoThread();
|
||||||
|
@ -2141,8 +2145,7 @@ void OBSBasic::OnFirstLoad()
|
||||||
/* shows a "what's new" page on startup of new versions using CEF */
|
/* shows a "what's new" page on startup of new versions using CEF */
|
||||||
void OBSBasic::ReceivedIntroJson(const QString &text)
|
void OBSBasic::ReceivedIntroJson(const QString &text)
|
||||||
{
|
{
|
||||||
#ifdef BROWSER_AVAILABLE
|
#ifdef WHATSNEW_ENABLED
|
||||||
#ifdef _WIN32
|
|
||||||
if (closing)
|
if (closing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2229,9 +2232,6 @@ void OBSBasic::ReceivedIntroJson(const QString &text)
|
||||||
whatsNewInitThread.reset(wnbit);
|
whatsNewInitThread.reset(wnbit);
|
||||||
whatsNewInitThread->start();
|
whatsNewInitThread->start();
|
||||||
|
|
||||||
#else
|
|
||||||
UNUSED_PARAMETER(text);
|
|
||||||
#endif
|
|
||||||
#else
|
#else
|
||||||
UNUSED_PARAMETER(text);
|
UNUSED_PARAMETER(text);
|
||||||
#endif
|
#endif
|
||||||
|
@ -2243,7 +2243,6 @@ void OBSBasic::ReceivedIntroJson(const QString &text)
|
||||||
void OBSBasic::ShowWhatsNew(const QString &url)
|
void OBSBasic::ShowWhatsNew(const QString &url)
|
||||||
{
|
{
|
||||||
#ifdef BROWSER_AVAILABLE
|
#ifdef BROWSER_AVAILABLE
|
||||||
#ifdef _WIN32
|
|
||||||
if (closing)
|
if (closing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -2282,9 +2281,6 @@ void OBSBasic::ShowWhatsNew(const QString &url)
|
||||||
#else
|
#else
|
||||||
UNUSED_PARAMETER(url);
|
UNUSED_PARAMETER(url);
|
||||||
#endif
|
#endif
|
||||||
#else
|
|
||||||
UNUSED_PARAMETER(url);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void OBSBasic::UpdateMultiviewProjectorMenu()
|
void OBSBasic::UpdateMultiviewProjectorMenu()
|
||||||
|
|
|
@ -4,10 +4,10 @@ if(OS_WINDOWS)
|
||||||
endif()
|
endif()
|
||||||
add_subdirectory(ipc-util)
|
add_subdirectory(ipc-util)
|
||||||
|
|
||||||
add_subdirectory(blake2)
|
|
||||||
add_subdirectory(lzma)
|
add_subdirectory(lzma)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(blake2)
|
||||||
add_subdirectory(glad)
|
add_subdirectory(glad)
|
||||||
add_subdirectory(media-playback)
|
add_subdirectory(media-playback)
|
||||||
add_subdirectory(file-updater)
|
add_subdirectory(file-updater)
|
||||||
|
|
Loading…
Reference in New Issue