mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-07-10 17:25:09 +03:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
137298e05a | ||
|
|
685a89a171 | ||
|
|
12b5cc7f72 | ||
|
|
480e9e8234 | ||
|
|
29e1852a68 | ||
|
|
8314335b31 | ||
|
|
acb9f63e1d | ||
|
|
005a8b4a04 | ||
|
|
e2149974cc |
85
.github/workflows/wf-cliprdr-ci.yml
vendored
85
.github/workflows/wf-cliprdr-ci.yml
vendored
@@ -1,85 +0,0 @@
|
|||||||
name: wf-cliprdr CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
pull_request:
|
|
||||||
paths:
|
|
||||||
- "libs/clipboard/src/windows/**"
|
|
||||||
- "tests/test_invariant_wf_cliprdr.c"
|
|
||||||
- ".github/workflows/wf-cliprdr-ci.yml"
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- master
|
|
||||||
paths:
|
|
||||||
- "libs/clipboard/src/windows/**"
|
|
||||||
- "tests/test_invariant_wf_cliprdr.c"
|
|
||||||
- ".github/workflows/wf-cliprdr-ci.yml"
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
concurrency:
|
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
|
||||||
cancel-in-progress: true
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test:
|
|
||||||
name: wf_cliprdr invariant test
|
|
||||||
runs-on: windows-2022
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout source code
|
|
||||||
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
||||||
with:
|
|
||||||
persist-credentials: false
|
|
||||||
|
|
||||||
- name: Set up MSVC
|
|
||||||
uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756
|
|
||||||
with:
|
|
||||||
arch: x64
|
|
||||||
|
|
||||||
- name: Setup vcpkg with GitHub Actions binary cache
|
|
||||||
uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11
|
|
||||||
with:
|
|
||||||
vcpkgDirectory: C:\vcpkg
|
|
||||||
doNotCache: false
|
|
||||||
|
|
||||||
- name: Install vcpkg dependency
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
& "$env:VCPKG_ROOT\vcpkg.exe" install check:x64-windows --classic --x-install-root="$env:VCPKG_ROOT\installed"
|
|
||||||
|
|
||||||
- name: Build test
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$testRoot = Join-Path $env:GITHUB_WORKSPACE 'build\wf-cliprdr'
|
|
||||||
New-Item -ItemType Directory -Force $testRoot | Out-Null
|
|
||||||
|
|
||||||
$testSource = (($env:GITHUB_WORKSPACE -replace '\\', '/') + '/tests/test_invariant_wf_cliprdr.c')
|
|
||||||
$cmakeLists = @(
|
|
||||||
'cmake_minimum_required(VERSION 3.20)'
|
|
||||||
'project(test_invariant_wf_cliprdr C)'
|
|
||||||
''
|
|
||||||
'set(CMAKE_C_STANDARD 11)'
|
|
||||||
'set(CMAKE_C_STANDARD_REQUIRED ON)'
|
|
||||||
'set(CMAKE_C_EXTENSIONS OFF)'
|
|
||||||
''
|
|
||||||
'find_package(check CONFIG REQUIRED)'
|
|
||||||
''
|
|
||||||
'add_executable(test_invariant_wf_cliprdr'
|
|
||||||
' "TEST_SOURCE"'
|
|
||||||
')'
|
|
||||||
''
|
|
||||||
'target_link_libraries(test_invariant_wf_cliprdr PRIVATE'
|
|
||||||
' $<$<TARGET_EXISTS:Check::check>:Check::check>'
|
|
||||||
' $<$<NOT:$<TARGET_EXISTS:Check::check>>:Check::checkShared>'
|
|
||||||
')'
|
|
||||||
) -join [Environment]::NewLine
|
|
||||||
$cmakeLists.Replace('TEST_SOURCE', $testSource) | Set-Content -NoNewline (Join-Path $testRoot 'CMakeLists.txt')
|
|
||||||
|
|
||||||
cmake -S $testRoot -B (Join-Path $testRoot 'out') -G "Visual Studio 17 2022" -A x64 -DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_ROOT\scripts\buildsystems\vcpkg.cmake" -DVCPKG_TARGET_TRIPLET=x64-windows
|
|
||||||
cmake --build (Join-Path $testRoot 'out') --config Release
|
|
||||||
|
|
||||||
- name: Run test
|
|
||||||
shell: pwsh
|
|
||||||
run: .\build\wf-cliprdr\out\Release\test_invariant_wf_cliprdr.exe
|
|
||||||
@@ -6,83 +6,82 @@ ANDROID_ABI=$1
|
|||||||
|
|
||||||
# Build RustDesk dependencies for Android using vcpkg.json
|
# Build RustDesk dependencies for Android using vcpkg.json
|
||||||
# Required:
|
# Required:
|
||||||
# 1. set VCPKG_ROOT / ANDROID_NDK path environment variables
|
# 1. set VCPKG_ROOT / ANDROID_NDK_HOME path environment variables
|
||||||
# 2. vcpkg initialized
|
# 2. vcpkg initialized
|
||||||
# 3. ndk, version: r25c or newer
|
# 3. ndk, version: r25c or newer
|
||||||
|
|
||||||
if [ -z "$ANDROID_NDK_HOME" ]; then
|
if [ -z "${ANDROID_NDK_HOME}" ]; then
|
||||||
echo "Failed! Please set ANDROID_NDK_HOME"
|
echo "ERROR: Please set ANDROID_NDK_HOME environment variable" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -z "$VCPKG_ROOT" ]; then
|
if [ -z "${VCPKG_ROOT}" ]; then
|
||||||
echo "Failed! Please set VCPKG_ROOT"
|
echo "ERROR: Please set VCPKG_ROOT environment variable" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
API_LEVEL="21"
|
case "${ANDROID_ABI}" in
|
||||||
|
arm64-v8a)
|
||||||
|
VCPKG_TARGET=arm64-android
|
||||||
|
;;
|
||||||
|
armeabi-v7a)
|
||||||
|
VCPKG_TARGET=arm-neon-android
|
||||||
|
;;
|
||||||
|
x86_64)
|
||||||
|
VCPKG_TARGET=x64-android
|
||||||
|
;;
|
||||||
|
x86)
|
||||||
|
VCPKG_TARGET=x86-android
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
echo "Usage: build_android_deps.sh <arm64-v8a|armeabi-v7a|x86_64|x86>" 1>&2
|
||||||
|
exit 1
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
# Get directory of this script
|
# Get directory of this script
|
||||||
|
|
||||||
SCRIPTDIR="$(readlink -f "$0")"
|
SCRIPTDIR="$(readlink -f "$0")"
|
||||||
SCRIPTDIR="$(dirname "$SCRIPTDIR")"
|
SCRIPTDIR="$(dirname "${SCRIPTDIR}")"
|
||||||
|
|
||||||
# Check if vcpkg.json is one level up - in root directory of RD
|
# Check if vcpkg.json is one level up - in root directory of RD
|
||||||
|
|
||||||
if [ ! -f "$SCRIPTDIR/../vcpkg.json" ]; then
|
if [ ! -f "${SCRIPTDIR}/../vcpkg.json" ]; then
|
||||||
echo "Failed! Please check where vcpkg.json is!"
|
echo "ERROR: Can not find vcpkg.json in RustDesk top-level directory" 1>&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# NDK llvm toolchain
|
echo "INFO: Building and install vcpkg dependencies for Android ${ANDROID_ABI} ..."
|
||||||
|
|
||||||
HOST_TAG="linux-x86_64" # current platform, set as `ls $ANDROID_NDK/toolchains/llvm/prebuilt/`
|
pushd "${SCRIPTDIR}/.."
|
||||||
TOOLCHAIN=$ANDROID_NDK/toolchains/llvm/prebuilt/$HOST_TAG
|
|
||||||
|
|
||||||
function build {
|
"${VCPKG_ROOT}/vcpkg" install \
|
||||||
ANDROID_ABI=$1
|
--triplet "${VCPKG_TARGET}" \
|
||||||
|
--x-install-root="${VCPKG_ROOT}/installed"
|
||||||
|
|
||||||
case "$ANDROID_ABI" in
|
popd
|
||||||
arm64-v8a)
|
|
||||||
ABI=aarch64-linux-android$API_LEVEL
|
|
||||||
VCPKG_TARGET=arm64-android
|
|
||||||
;;
|
|
||||||
armeabi-v7a)
|
|
||||||
ABI=armv7a-linux-androideabi$API_LEVEL
|
|
||||||
VCPKG_TARGET=arm-neon-android
|
|
||||||
;;
|
|
||||||
x86_64)
|
|
||||||
ABI=x86_64-linux-android$API_LEVEL
|
|
||||||
VCPKG_TARGET=x64-android
|
|
||||||
;;
|
|
||||||
x86)
|
|
||||||
ABI=i686-linux-android$API_LEVEL
|
|
||||||
VCPKG_TARGET=x86-android
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "ERROR: ANDROID_ABI must be one of: arm64-v8a, armeabi-v7a, x86_64, x86" >&2
|
|
||||||
return 1
|
|
||||||
esac
|
|
||||||
|
|
||||||
echo "*** [$ANDROID_ABI][Start] Build and install vcpkg dependencies"
|
echo "INFO: Completed building vcpkg dependencies for Android ${ANDROID_ABI}"
|
||||||
pushd "$SCRIPTDIR/.."
|
|
||||||
$VCPKG_ROOT/vcpkg install --triplet $VCPKG_TARGET --x-install-root="$VCPKG_ROOT/installed"
|
|
||||||
popd
|
|
||||||
head -n 100 "${VCPKG_ROOT}/buildtrees/ffmpeg/build-$VCPKG_TARGET-rel-out.log" || true
|
|
||||||
echo "*** [$ANDROID_ABI][Finished] Build and install vcpkg dependencies"
|
|
||||||
|
|
||||||
if [ -d "$VCPKG_ROOT/installed/arm-neon-android" ]; then
|
if [ "${ANDROID_ABI}" = 'armeabi-v7a' ]; then
|
||||||
echo "*** [Start] Move arm-neon-android to arm-android"
|
# Symlink arm-neon-android to arm-android because cargo-ndk does not
|
||||||
|
# understand NEON suffix.
|
||||||
|
|
||||||
mv "$VCPKG_ROOT/installed/arm-neon-android" "$VCPKG_ROOT/installed/arm-android"
|
if [ -d "${VCPKG_ROOT}/installed/arm-neon-android" ]; then
|
||||||
|
echo 'INFO: Symlinking arm-neon-android to arm-android'
|
||||||
|
|
||||||
echo "*** [Finished] Move arm-neon-android to arm-android"
|
ln -sf \
|
||||||
fi
|
"${VCPKG_ROOT}/installed/arm-neon-android" \
|
||||||
}
|
"${VCPKG_ROOT}/installed/arm-android"
|
||||||
|
|
||||||
if [ ! -z "$ANDROID_ABI" ]; then
|
echo 'INFO: Symlinked arm-neon-android to arm-android'
|
||||||
build "$ANDROID_ABI"
|
else
|
||||||
else
|
cat 0<<.a
|
||||||
echo "Usage: build-android-deps.sh <ANDROID-ABI>" >&2
|
ERROR: 'vcpkg install' seem to complete successfully but
|
||||||
exit 1
|
directory '${VCPKG_ROOT}/installed/arm-neon-android' is missing!
|
||||||
|
|
||||||
|
.a
|
||||||
|
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -232,6 +232,7 @@ struct _CliprdrStream
|
|||||||
FILEDESCRIPTORW m_Dsc;
|
FILEDESCRIPTORW m_Dsc;
|
||||||
void *m_pData;
|
void *m_pData;
|
||||||
UINT32 m_connID;
|
UINT32 m_connID;
|
||||||
|
UINT32 m_streamId; // unique CLIPRDR streamId; avoids leaking a heap pointer
|
||||||
};
|
};
|
||||||
typedef struct _CliprdrStream CliprdrStream;
|
typedef struct _CliprdrStream CliprdrStream;
|
||||||
|
|
||||||
@@ -285,6 +286,9 @@ struct wf_clipboard
|
|||||||
char *req_fdata;
|
char *req_fdata;
|
||||||
HANDLE req_fevent;
|
HANDLE req_fevent;
|
||||||
BOOL req_f_received;
|
BOOL req_f_received;
|
||||||
|
UINT32 req_f_conn_id_expected; // connID of the outstanding request
|
||||||
|
UINT32 req_f_stream_id_expected; // streamId of the outstanding request; responses for another are dropped
|
||||||
|
LONG req_f_stream_id_seq; // source of unique per-stream ids
|
||||||
|
|
||||||
size_t nFiles;
|
size_t nFiles;
|
||||||
size_t file_array_size;
|
size_t file_array_size;
|
||||||
@@ -315,7 +319,7 @@ static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format);
|
|||||||
static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 format);
|
static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 format);
|
||||||
static UINT cliprdr_send_lock(wfClipboard *clipboard);
|
static UINT cliprdr_send_lock(wfClipboard *clipboard);
|
||||||
static UINT cliprdr_send_unlock(wfClipboard *clipboard);
|
static UINT cliprdr_send_unlock(wfClipboard *clipboard);
|
||||||
static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid,
|
static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, UINT32 streamId,
|
||||||
ULONG index, UINT32 flag, DWORD positionhigh,
|
ULONG index, UINT32 flag, DWORD positionhigh,
|
||||||
DWORD positionlow, ULONG request);
|
DWORD positionlow, ULONG request);
|
||||||
|
|
||||||
@@ -398,7 +402,7 @@ static ULONG STDMETHODCALLTYPE CliprdrStream_Release(IStream *This)
|
|||||||
static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream *This, void *pv, ULONG cb,
|
static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream *This, void *pv, ULONG cb,
|
||||||
ULONG *pcbRead)
|
ULONG *pcbRead)
|
||||||
{
|
{
|
||||||
int ret;
|
UINT ret;
|
||||||
CliprdrStream *instance = (CliprdrStream *)This;
|
CliprdrStream *instance = (CliprdrStream *)This;
|
||||||
wfClipboard *clipboard;
|
wfClipboard *clipboard;
|
||||||
|
|
||||||
@@ -411,12 +415,23 @@ static HRESULT STDMETHODCALLTYPE CliprdrStream_Read(IStream *This, void *pv, ULO
|
|||||||
if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart)
|
if (instance->m_lOffset.QuadPart >= instance->m_lSize.QuadPart)
|
||||||
return S_FALSE;
|
return S_FALSE;
|
||||||
|
|
||||||
ret = cliprdr_send_request_filecontents(clipboard, instance->m_connID, (void *)This, instance->m_lIndex,
|
ret = cliprdr_send_request_filecontents(clipboard, instance->m_connID, instance->m_streamId, instance->m_lIndex,
|
||||||
FILECONTENTS_RANGE, instance->m_lOffset.HighPart,
|
FILECONTENTS_RANGE, instance->m_lOffset.HighPart,
|
||||||
instance->m_lOffset.LowPart, cb);
|
instance->m_lOffset.LowPart, cb);
|
||||||
|
|
||||||
if (ret < 0)
|
if (ret != CHANNEL_RC_OK)
|
||||||
|
{
|
||||||
|
free(clipboard->req_fdata);
|
||||||
|
clipboard->req_fdata = NULL;
|
||||||
return E_FAIL;
|
return E_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clipboard->req_fsize > cb)
|
||||||
|
{
|
||||||
|
free(clipboard->req_fdata);
|
||||||
|
clipboard->req_fdata = NULL;
|
||||||
|
return STG_E_READFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
if (clipboard->req_fdata)
|
if (clipboard->req_fdata)
|
||||||
{
|
{
|
||||||
@@ -628,6 +643,7 @@ static CliprdrStream *CliprdrStream_New(UINT32 connID, ULONG index, void *pData,
|
|||||||
instance->m_pData = pData;
|
instance->m_pData = pData;
|
||||||
instance->m_lOffset.QuadPart = 0;
|
instance->m_lOffset.QuadPart = 0;
|
||||||
instance->m_connID = connID;
|
instance->m_connID = connID;
|
||||||
|
instance->m_streamId = (UINT32)InterlockedIncrement(&clipboard->req_f_stream_id_seq);
|
||||||
|
|
||||||
if (instance->m_Dsc.dwFlags & FD_ATTRIBUTES)
|
if (instance->m_Dsc.dwFlags & FD_ATTRIBUTES)
|
||||||
{
|
{
|
||||||
@@ -638,16 +654,28 @@ static CliprdrStream *CliprdrStream_New(UINT32 connID, ULONG index, void *pData,
|
|||||||
if (((instance->m_Dsc.dwFlags & FD_FILESIZE) == 0) && !isDir)
|
if (((instance->m_Dsc.dwFlags & FD_FILESIZE) == 0) && !isDir)
|
||||||
{
|
{
|
||||||
/* get content size of this stream */
|
/* get content size of this stream */
|
||||||
if (cliprdr_send_request_filecontents(clipboard, instance->m_connID, (void *)instance,
|
if (cliprdr_send_request_filecontents(clipboard, instance->m_connID, instance->m_streamId,
|
||||||
instance->m_lIndex, FILECONTENTS_SIZE, 0, 0,
|
instance->m_lIndex, FILECONTENTS_SIZE, 0, 0,
|
||||||
8) == CHANNEL_RC_OK)
|
8) == CHANNEL_RC_OK)
|
||||||
{
|
{
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clipboard->req_fdata != NULL)
|
if (clipboard->req_fdata != NULL && clipboard->req_fsize >= sizeof(LONGLONG))
|
||||||
|
{
|
||||||
|
LONGLONG sz = 0;
|
||||||
|
CopyMemory(&sz, clipboard->req_fdata, sizeof(sz));
|
||||||
|
if (sz < 0)
|
||||||
|
success = FALSE;
|
||||||
|
else
|
||||||
|
instance->m_lSize.QuadPart = sz;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
success = FALSE;
|
||||||
|
}
|
||||||
|
if (clipboard->req_fdata)
|
||||||
{
|
{
|
||||||
instance->m_lSize.QuadPart = *((LONGLONG *)clipboard->req_fdata);
|
|
||||||
free(clipboard->req_fdata);
|
free(clipboard->req_fdata);
|
||||||
clipboard->req_fdata = NULL;
|
clipboard->req_fdata = NULL;
|
||||||
}
|
}
|
||||||
@@ -1773,12 +1801,12 @@ static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UIN
|
|||||||
return wait_response_event(connID, clipboard, clipboard->formatDataRespEvent, &clipboard->formatDataRespReceived, &clipboard->hmem);
|
return wait_response_event(connID, clipboard, clipboard->formatDataRespEvent, &clipboard->formatDataRespReceived, &clipboard->hmem);
|
||||||
}
|
}
|
||||||
|
|
||||||
UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index,
|
static UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, UINT32 streamId, ULONG index,
|
||||||
UINT32 flag, DWORD positionhigh, DWORD positionlow,
|
UINT32 flag, DWORD positionhigh, DWORD positionlow,
|
||||||
ULONG nreq)
|
ULONG nreq)
|
||||||
{
|
{
|
||||||
UINT rc;
|
UINT rc;
|
||||||
CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest;
|
CLIPRDR_FILE_CONTENTS_REQUEST fileContentsRequest = { 0 };
|
||||||
|
|
||||||
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsRequest)
|
if (!clipboard || !clipboard->context || !clipboard->context->ClientFileContentsRequest)
|
||||||
return ERROR_INTERNAL_ERROR;
|
return ERROR_INTERNAL_ERROR;
|
||||||
@@ -1789,12 +1817,11 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, co
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
clipboard->req_f_received = FALSE;
|
clipboard->req_f_received = FALSE;
|
||||||
|
clipboard->req_f_conn_id_expected = connID;
|
||||||
|
clipboard->req_f_stream_id_expected = streamId;
|
||||||
|
|
||||||
fileContentsRequest.connID = connID;
|
fileContentsRequest.connID = connID;
|
||||||
// streamId is `IStream*` pointer, though it is not very good on a 64-bit system.
|
fileContentsRequest.streamId = streamId;
|
||||||
// But it is OK, because it is only used to check if the stream is the same in
|
|
||||||
// `wf_cliprdr_server_file_contents_request()` function.
|
|
||||||
fileContentsRequest.streamId = (UINT32)(ULONG_PTR)streamid;
|
|
||||||
fileContentsRequest.listIndex = index;
|
fileContentsRequest.listIndex = index;
|
||||||
fileContentsRequest.dwFlags = flag;
|
fileContentsRequest.dwFlags = flag;
|
||||||
fileContentsRequest.nPositionLow = positionlow;
|
fileContentsRequest.nPositionLow = positionlow;
|
||||||
@@ -3015,6 +3042,7 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
|
|||||||
BOOL bIsStreamFile = TRUE;
|
BOOL bIsStreamFile = TRUE;
|
||||||
static LPSTREAM pStreamStc = NULL;
|
static LPSTREAM pStreamStc = NULL;
|
||||||
static UINT32 uStreamIdStc = 0;
|
static UINT32 uStreamIdStc = 0;
|
||||||
|
static UINT32 uConnIdStc = 0;
|
||||||
wfClipboard *clipboard;
|
wfClipboard *clipboard;
|
||||||
UINT rc = ERROR_INTERNAL_ERROR;
|
UINT rc = ERROR_INTERNAL_ERROR;
|
||||||
UINT sRc;
|
UINT sRc;
|
||||||
@@ -3088,7 +3116,8 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
|
|||||||
vFormatEtc.lindex = fileContentsRequest->listIndex;
|
vFormatEtc.lindex = fileContentsRequest->listIndex;
|
||||||
vFormatEtc.ptd = NULL;
|
vFormatEtc.ptd = NULL;
|
||||||
|
|
||||||
if ((uStreamIdStc != fileContentsRequest->streamId) || !pStreamStc)
|
if ((uStreamIdStc != fileContentsRequest->streamId) ||
|
||||||
|
(uConnIdStc != fileContentsRequest->connID) || !pStreamStc)
|
||||||
{
|
{
|
||||||
LPENUMFORMATETC pEnumFormatEtc;
|
LPENUMFORMATETC pEnumFormatEtc;
|
||||||
ULONG CeltFetched;
|
ULONG CeltFetched;
|
||||||
@@ -3119,6 +3148,7 @@ wf_cliprdr_server_file_contents_request(CliprdrClientContext *context,
|
|||||||
{
|
{
|
||||||
pStreamStc = vStgMedium.pstm;
|
pStreamStc = vStgMedium.pstm;
|
||||||
uStreamIdStc = fileContentsRequest->streamId;
|
uStreamIdStc = fileContentsRequest->streamId;
|
||||||
|
uConnIdStc = fileContentsRequest->connID;
|
||||||
bIsStreamFile = TRUE;
|
bIsStreamFile = TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3282,6 +3312,9 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
|
|||||||
rc = ERROR_INTERNAL_ERROR;
|
rc = ERROR_INTERNAL_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (fileContentsResponse->connID != clipboard->req_f_conn_id_expected ||
|
||||||
|
fileContentsResponse->streamId != clipboard->req_f_stream_id_expected)
|
||||||
|
return CHANNEL_RC_OK;
|
||||||
clipboard->req_fsize = 0;
|
clipboard->req_fsize = 0;
|
||||||
clipboard->req_fdata = NULL;
|
clipboard->req_fdata = NULL;
|
||||||
|
|
||||||
@@ -3292,6 +3325,13 @@ wf_cliprdr_server_file_contents_response(CliprdrClientContext *context,
|
|||||||
}
|
}
|
||||||
|
|
||||||
clipboard->req_fsize = fileContentsResponse->cbRequested;
|
clipboard->req_fsize = fileContentsResponse->cbRequested;
|
||||||
|
/*
|
||||||
|
* Keep the zero-size allocation: supported Windows builds use the Microsoft
|
||||||
|
* CRT, where malloc(0) returns a valid pointer. wait_response_event() also
|
||||||
|
* uses a non-NULL req_fdata to recognize a successful zero-byte response.
|
||||||
|
* The Rust FFI derives requestedData and cbRequested from the same Vec, so a
|
||||||
|
* nonzero length cannot have a NULL data pointer on the normal call path.
|
||||||
|
*/
|
||||||
clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested);
|
clipboard->req_fdata = (char *)malloc(fileContentsResponse->cbRequested);
|
||||||
if (!clipboard->req_fdata)
|
if (!clipboard->req_fdata)
|
||||||
{
|
{
|
||||||
|
|||||||
7
res/vcpkg-triplets/arm-neon-android.cmake
Normal file
7
res/vcpkg-triplets/arm-neon-android.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set(VCPKG_TARGET_ARCHITECTURE arm)
|
||||||
|
set(VCPKG_CRT_LINKAGE dynamic)
|
||||||
|
set(VCPKG_LIBRARY_LINKAGE static)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_NAME Android)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_VERSION 21)
|
||||||
|
set(VCPKG_MAKE_BUILD_TRIPLET "--host=armv7a-linux-androideabi")
|
||||||
|
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON)
|
||||||
7
res/vcpkg-triplets/arm64-android.cmake
Normal file
7
res/vcpkg-triplets/arm64-android.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set(VCPKG_TARGET_ARCHITECTURE arm64)
|
||||||
|
set(VCPKG_CRT_LINKAGE dynamic)
|
||||||
|
set(VCPKG_LIBRARY_LINKAGE static)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_NAME Android)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_VERSION 21)
|
||||||
|
set(VCPKG_MAKE_BUILD_TRIPLET "--host=aarch64-linux-android")
|
||||||
|
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DANDROID_ABI=arm64-v8a)
|
||||||
7
res/vcpkg-triplets/x64-android.cmake
Normal file
7
res/vcpkg-triplets/x64-android.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set(VCPKG_TARGET_ARCHITECTURE x64)
|
||||||
|
set(VCPKG_CRT_LINKAGE dynamic)
|
||||||
|
set(VCPKG_LIBRARY_LINKAGE static)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_NAME Android)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_VERSION 21)
|
||||||
|
set(VCPKG_MAKE_BUILD_TRIPLET "--host=x86_64-linux-android")
|
||||||
|
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DANDROID_ABI=x86_64)
|
||||||
7
res/vcpkg-triplets/x86-android.cmake
Normal file
7
res/vcpkg-triplets/x86-android.cmake
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
set(VCPKG_TARGET_ARCHITECTURE x86)
|
||||||
|
set(VCPKG_CRT_LINKAGE dynamic)
|
||||||
|
set(VCPKG_LIBRARY_LINKAGE static)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_NAME Android)
|
||||||
|
set(VCPKG_CMAKE_SYSTEM_VERSION 21)
|
||||||
|
set(VCPKG_MAKE_BUILD_TRIPLET "--host=i686-linux-android")
|
||||||
|
set(VCPKG_CMAKE_CONFIGURE_OPTIONS -DANDROID_ABI=x86)
|
||||||
@@ -9,8 +9,8 @@ mod http_client;
|
|||||||
pub mod record_upload;
|
pub mod record_upload;
|
||||||
pub mod sync;
|
pub mod sync;
|
||||||
pub use http_client::{
|
pub use http_client::{
|
||||||
create_http_client_async, create_http_client_async_with_url, create_http_client_with_url,
|
create_http_client_async, create_http_client_async_with_url_strict,
|
||||||
get_url_for_tls,
|
create_http_client_with_url, create_http_client_with_url_strict, get_url_for_tls,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::create_http_client_async_with_url;
|
use super::create_http_client_async_with_url_strict;
|
||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
bail,
|
bail,
|
||||||
lazy_static::lazy_static,
|
lazy_static::lazy_static,
|
||||||
@@ -167,7 +167,7 @@ async fn do_download(
|
|||||||
auto_del_dur: Option<Duration>,
|
auto_del_dur: Option<Duration>,
|
||||||
mut rx_cancel: UnboundedReceiver<()>,
|
mut rx_cancel: UnboundedReceiver<()>,
|
||||||
) -> ResultType<bool> {
|
) -> ResultType<bool> {
|
||||||
let client = create_http_client_async_with_url(&url).await;
|
let client = create_http_client_async_with_url_strict(&url).await?;
|
||||||
|
|
||||||
let mut is_all_downloaded = false;
|
let mut is_all_downloaded = false;
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
use hbb_common::{
|
use hbb_common::{
|
||||||
async_recursion::async_recursion,
|
async_recursion::async_recursion,
|
||||||
|
bail,
|
||||||
config::{Config, Socks5Server},
|
config::{Config, Socks5Server},
|
||||||
log::{self, info},
|
log::{self, info},
|
||||||
proxy::{Proxy, ProxyScheme},
|
proxy::{Proxy, ProxyScheme},
|
||||||
@@ -7,6 +8,7 @@ use hbb_common::{
|
|||||||
get_cached_tls_accept_invalid_cert, get_cached_tls_type, is_plain, upsert_tls_cache,
|
get_cached_tls_accept_invalid_cert, get_cached_tls_type, is_plain, upsert_tls_cache,
|
||||||
TlsType,
|
TlsType,
|
||||||
},
|
},
|
||||||
|
ResultType,
|
||||||
};
|
};
|
||||||
use reqwest::{blocking::Client as SyncClient, Client as AsyncClient};
|
use reqwest::{blocking::Client as SyncClient, Client as AsyncClient};
|
||||||
|
|
||||||
@@ -137,6 +139,32 @@ pub fn create_http_client_with_url(url: &str) -> SyncClient {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn create_http_client_with_url_strict(url: &str) -> ResultType<SyncClient> {
|
||||||
|
let parsed_url = url::Url::parse(url)?;
|
||||||
|
if parsed_url.scheme() != "https" {
|
||||||
|
bail!("Strict HTTP client requires HTTPS: {}", url);
|
||||||
|
}
|
||||||
|
let proxy_conf = Config::get_socks();
|
||||||
|
let tls_url = get_url_for_tls(url, &proxy_conf);
|
||||||
|
let cached_tls_type = get_cached_tls_type(tls_url);
|
||||||
|
let cached_danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
||||||
|
let can_reuse_cached_probe =
|
||||||
|
cached_tls_type.is_some() && cached_danger_accept_invalid_cert == Some(false);
|
||||||
|
let tls_type = if can_reuse_cached_probe {
|
||||||
|
cached_tls_type.unwrap_or(TlsType::Rustls)
|
||||||
|
} else {
|
||||||
|
TlsType::Rustls
|
||||||
|
};
|
||||||
|
Ok(create_http_client_with_url_(
|
||||||
|
url,
|
||||||
|
tls_url,
|
||||||
|
tls_type,
|
||||||
|
can_reuse_cached_probe,
|
||||||
|
Some(false),
|
||||||
|
Some(false),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn create_http_client_with_url_(
|
fn create_http_client_with_url_(
|
||||||
url: &str,
|
url: &str,
|
||||||
tls_url: &str,
|
tls_url: &str,
|
||||||
@@ -247,6 +275,33 @@ pub async fn create_http_client_async_with_url(url: &str) -> AsyncClient {
|
|||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn create_http_client_async_with_url_strict(url: &str) -> ResultType<AsyncClient> {
|
||||||
|
let parsed_url = url::Url::parse(url)?;
|
||||||
|
if parsed_url.scheme() != "https" {
|
||||||
|
bail!("Strict HTTP client requires HTTPS: {}", url);
|
||||||
|
}
|
||||||
|
let proxy_conf = Config::get_socks();
|
||||||
|
let tls_url = get_url_for_tls(url, &proxy_conf);
|
||||||
|
let cached_tls_type = get_cached_tls_type(tls_url);
|
||||||
|
let cached_danger_accept_invalid_cert = get_cached_tls_accept_invalid_cert(tls_url);
|
||||||
|
let can_reuse_cached_probe =
|
||||||
|
cached_tls_type.is_some() && cached_danger_accept_invalid_cert == Some(false);
|
||||||
|
let tls_type = if can_reuse_cached_probe {
|
||||||
|
cached_tls_type.unwrap_or(TlsType::Rustls)
|
||||||
|
} else {
|
||||||
|
TlsType::Rustls
|
||||||
|
};
|
||||||
|
Ok(create_http_client_async_with_url_(
|
||||||
|
url,
|
||||||
|
tls_url,
|
||||||
|
tls_type,
|
||||||
|
can_reuse_cached_probe,
|
||||||
|
Some(false),
|
||||||
|
Some(false),
|
||||||
|
)
|
||||||
|
.await)
|
||||||
|
}
|
||||||
|
|
||||||
#[async_recursion]
|
#[async_recursion]
|
||||||
async fn create_http_client_async_with_url_(
|
async fn create_http_client_async_with_url_(
|
||||||
url: &str,
|
url: &str,
|
||||||
|
|||||||
@@ -332,7 +332,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Relay Connection", "Connessione relay"),
|
("Relay Connection", "Connessione relay"),
|
||||||
("Secure Connection", "Connessione sicura"),
|
("Secure Connection", "Connessione sicura"),
|
||||||
("Insecure Connection", "Connessione non sicura"),
|
("Insecure Connection", "Connessione non sicura"),
|
||||||
("Continue", ""),
|
("Continue", "Continua"),
|
||||||
("Scale original", "Scala originale"),
|
("Scale original", "Scala originale"),
|
||||||
("Scale adaptive", "Scala adattiva"),
|
("Scale adaptive", "Scala adattiva"),
|
||||||
("General", "Generale"),
|
("General", "Generale"),
|
||||||
@@ -764,6 +764,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Show on the minimized toolbar", "Visualizza nella barra strumenti ridotta a icona"),
|
("Show on the minimized toolbar", "Visualizza nella barra strumenti ridotta a icona"),
|
||||||
("All monitors", "Tutti gli schermi"),
|
("All monitors", "Tutti gli schermi"),
|
||||||
("#{} monitor", "Schermo {}"),
|
("#{} monitor", "Schermo {}"),
|
||||||
("conn-e2ee-unavailable-tip", "Impossibile verificare la crittografia end-to-end.\nIl dispositivo remoto potrebbe essere ancora in configurazione. Riprova più tardi.\nSe il problema persiste, il server potrebbe non essere attendibile.\nContinuare comunque?"),
|
("conn-e2ee-unavailable-tip", "Impossibile verificare la crittografia end-to-end.\nIl dispositivo remoto potrebbe essere ancora in configurazione. Riprova più tardi.\nSe il problema persiste, il server potrebbe non essere attendibile.\nVuoi continuare?"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("id_change_tip", "a-z, A-Z, 0-9, -(대시) 및 _(밑줄) 문자만 허용됩니다. 첫 글자는 a-z, A-Z여야 합니다. 길이는 6에서 16 사이여야 합니다."),
|
("id_change_tip", "a-z, A-Z, 0-9, -(대시) 및 _(밑줄) 문자만 허용됩니다. 첫 글자는 a-z, A-Z여야 합니다. 길이는 6에서 16 사이여야 합니다."),
|
||||||
("Website", "웹사이트"),
|
("Website", "웹사이트"),
|
||||||
("About", "정보"),
|
("About", "정보"),
|
||||||
("Slogan_tip", "이 혼란스러운 세상에서 마음을 담아 만들었습니다!"),
|
("Slogan_tip", "이 혼란스러운 세상에서 마음을 담아 만들었습니다! - 한국어 번역: 비너스걸"),
|
||||||
("Privacy Statement", "개인정보 보호정책"),
|
("Privacy Statement", "개인정보 보호정책"),
|
||||||
("Mute", "음소거"),
|
("Mute", "음소거"),
|
||||||
("Build Date", "빌드 날짜"),
|
("Build Date", "빌드 날짜"),
|
||||||
@@ -332,7 +332,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Relay Connection", "릴레이 연결"),
|
("Relay Connection", "릴레이 연결"),
|
||||||
("Secure Connection", "보안 연결"),
|
("Secure Connection", "보안 연결"),
|
||||||
("Insecure Connection", "보안되지 않은 연결"),
|
("Insecure Connection", "보안되지 않은 연결"),
|
||||||
("Continue", ""),
|
|
||||||
("Scale original", "원본 크기 조정"),
|
("Scale original", "원본 크기 조정"),
|
||||||
("Scale adaptive", "크기 조정 가능"),
|
("Scale adaptive", "크기 조정 가능"),
|
||||||
("General", "일반"),
|
("General", "일반"),
|
||||||
@@ -764,6 +763,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
|
|||||||
("Show on the minimized toolbar", "최소화된 도구 모음에 표시"),
|
("Show on the minimized toolbar", "최소화된 도구 모음에 표시"),
|
||||||
("All monitors", "모든 모니터"),
|
("All monitors", "모든 모니터"),
|
||||||
("#{} monitor", "#{} 모니터"),
|
("#{} monitor", "#{} 모니터"),
|
||||||
("conn-e2ee-unavailable-tip", "종단 간 암호화를 확인할 수 없습니다.\n원격 장치가 아직 설정 중일 수 있습니다. 나중에 다시 시도하세요.\n이 문제가 계속되면 서버를 신뢰할 수 없을 수 있습니다.\n그래도 계속하시겠습니까?"),
|
("conn-e2ee-unavailable-tip", "종단 간 암호화를 확인할 수 없습니다.\n원격 장치가 여전히 설정 중일 수 있습니다. 나중에 다시 시도해 보세요.\n이런 일이 계속 발생하면 서버가 신뢰할 수 없을 수도 있습니다.\n어쨌든 계속하시겠습니까?"),
|
||||||
].iter().cloned().collect();
|
].iter().cloned().collect();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
use crate::{common::do_check_software_update, hbbs_http::create_http_client_with_url};
|
use crate::{common::do_check_software_update, hbbs_http::create_http_client_with_url_strict};
|
||||||
use hbb_common::{bail, config, log, ResultType};
|
use hbb_common::{bail, config, log, ResultType};
|
||||||
use std::{
|
use std::{
|
||||||
io::Write,
|
io::Write,
|
||||||
path::PathBuf,
|
path::{Component, Path, PathBuf},
|
||||||
sync::{
|
sync::{
|
||||||
atomic::{AtomicUsize, Ordering},
|
atomic::{AtomicUsize, Ordering},
|
||||||
mpsc::{channel, Receiver, Sender},
|
mpsc::{channel, Receiver, Sender},
|
||||||
@@ -153,7 +153,7 @@ fn check_update(manually: bool) -> ResultType<()> {
|
|||||||
format!("{}/rustdesk-{}-x86-sciter.exe", download_url, version)
|
format!("{}/rustdesk-{}-x86-sciter.exe", download_url, version)
|
||||||
};
|
};
|
||||||
log::debug!("New version available: {}", &version);
|
log::debug!("New version available: {}", &version);
|
||||||
let client = create_http_client_with_url(&download_url);
|
let client = create_http_client_with_url_strict(&download_url)?;
|
||||||
let Some(file_path) = get_download_file_from_url(&download_url) else {
|
let Some(file_path) = get_download_file_from_url(&download_url) else {
|
||||||
bail!("Failed to get the file path from the URL: {}", download_url);
|
bail!("Failed to get the file path from the URL: {}", download_url);
|
||||||
};
|
};
|
||||||
@@ -291,7 +291,96 @@ fn update_new_version(update_msi: bool, version: &str, file_path: &PathBuf) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_download_file_from_url(url: &str) -> Option<PathBuf> {
|
pub fn get_update_download_file_from_url(url: &str) -> Option<PathBuf> {
|
||||||
let filename = url.split('/').last()?;
|
let parsed = url::Url::parse(url).ok()?;
|
||||||
|
// Check the raw prefix before Url normalizes default ports.
|
||||||
|
if !url.starts_with("https://github.com/")
|
||||||
|
|| parsed.scheme() != "https"
|
||||||
|
|| parsed.host_str() != Some("github.com")
|
||||||
|
|| !parsed.username().is_empty()
|
||||||
|
|| parsed.password().is_some()
|
||||||
|
|| parsed.port().is_some()
|
||||||
|
|| parsed.query().is_some()
|
||||||
|
|| parsed.fragment().is_some()
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut segments = parsed.path_segments()?;
|
||||||
|
let owner = segments.next()?;
|
||||||
|
let repo = segments.next()?;
|
||||||
|
let releases = segments.next()?;
|
||||||
|
let download = segments.next()?;
|
||||||
|
let tag = segments.next()?;
|
||||||
|
let filename = segments.next()?;
|
||||||
|
|
||||||
|
if owner != "rustdesk"
|
||||||
|
|| repo != "rustdesk"
|
||||||
|
|| releases != "releases"
|
||||||
|
|| download != "download"
|
||||||
|
|| tag.is_empty()
|
||||||
|
|| segments.next().is_some()
|
||||||
|
|| !is_plain_update_filename(filename)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
Some(std::env::temp_dir().join(filename))
|
Some(std::env::temp_dir().join(filename))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_plain_update_filename(filename: &str) -> bool {
|
||||||
|
if filename.is_empty()
|
||||||
|
|| filename.contains('/')
|
||||||
|
|| filename.contains('\\')
|
||||||
|
|| filename.contains(':')
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut components = Path::new(filename).components();
|
||||||
|
matches!(
|
||||||
|
components.next(),
|
||||||
|
Some(Component::Normal(name)) if name.to_str() == Some(filename)
|
||||||
|
) && components.next().is_none()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_download_file_from_url(url: &str) -> Option<PathBuf> {
|
||||||
|
get_update_download_file_from_url(url)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::get_download_file_from_url;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_download_file_accepts_expected_github_asset_urls() {
|
||||||
|
let file = get_download_file_from_url(
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1.4.0/rustdesk-1.4.0-x86_64.dmg",
|
||||||
|
)
|
||||||
|
.expect("valid GitHub release asset URL");
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
file.file_name().and_then(|name| name.to_str()),
|
||||||
|
Some("rustdesk-1.4.0-x86_64.dmg")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn update_download_file_rejects_untrusted_or_malformed_urls() {
|
||||||
|
for url in [
|
||||||
|
"http://github.com/rustdesk/rustdesk/releases/download/1/rustdesk.exe",
|
||||||
|
"https://example.com/rustdesk.exe",
|
||||||
|
"https://github.com/other/project/releases/download/1/rustdesk.exe",
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1/",
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1/nested/rustdesk.exe",
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1/C:rustdesk.exe",
|
||||||
|
"https://user@github.com/rustdesk/rustdesk/releases/download/1/rustdesk.exe",
|
||||||
|
"https://github.com:443/rustdesk/rustdesk/releases/download/1/rustdesk.exe",
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1/rustdesk.exe?download=1",
|
||||||
|
"https://github.com/rustdesk/rustdesk/releases/download/1/rustdesk.exe#download",
|
||||||
|
"not a url",
|
||||||
|
] {
|
||||||
|
assert!(get_download_file_from_url(url).is_none(), "{url}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,92 +0,0 @@
|
|||||||
#include <check.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#include "../libs/clipboard/src/windows/wf_cliprdr.c"
|
|
||||||
|
|
||||||
static SIZE_T descriptor_size(UINT count)
|
|
||||||
{
|
|
||||||
return offsetof(FILEGROUPDESCRIPTORW, fgd) + (SIZE_T)count * sizeof(FILEDESCRIPTORW);
|
|
||||||
}
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_rejects_buffer_smaller_than_header)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid(0, 1), FALSE);
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid(
|
|
||||||
offsetof(FILEGROUPDESCRIPTORW, fgd) - 1, 1),
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_rejects_zero_items)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(
|
|
||||||
wf_cliprdr_file_group_descriptor_size_valid(offsetof(FILEGROUPDESCRIPTORW, fgd), 0),
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_accepts_max_stream_count)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid(
|
|
||||||
descriptor_size(WF_CLIPRDR_MAX_STREAMS), WF_CLIPRDR_MAX_STREAMS),
|
|
||||||
TRUE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_rejects_stream_count_above_limit)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid(
|
|
||||||
descriptor_size(WF_CLIPRDR_MAX_STREAMS), WF_CLIPRDR_MAX_STREAMS + 1),
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_rejects_truncated_descriptor_array)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid(descriptor_size(2) - 1, 2),
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
START_TEST(test_descriptor_size_rejects_extreme_count)
|
|
||||||
{
|
|
||||||
ck_assert_int_eq(wf_cliprdr_file_group_descriptor_size_valid((SIZE_T)-1, (UINT)-1),
|
|
||||||
FALSE);
|
|
||||||
}
|
|
||||||
END_TEST
|
|
||||||
|
|
||||||
Suite *wf_cliprdr_invariant_suite(void)
|
|
||||||
{
|
|
||||||
Suite *s;
|
|
||||||
TCase *tc_core;
|
|
||||||
|
|
||||||
s = suite_create("wf_cliprdr_invariants");
|
|
||||||
tc_core = tcase_create("descriptor_size");
|
|
||||||
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_rejects_buffer_smaller_than_header);
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_rejects_zero_items);
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_accepts_max_stream_count);
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_rejects_stream_count_above_limit);
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_rejects_truncated_descriptor_array);
|
|
||||||
tcase_add_test(tc_core, test_descriptor_size_rejects_extreme_count);
|
|
||||||
|
|
||||||
suite_add_tcase(s, tc_core);
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(void)
|
|
||||||
{
|
|
||||||
int number_failed;
|
|
||||||
Suite *s;
|
|
||||||
SRunner *sr;
|
|
||||||
|
|
||||||
s = wf_cliprdr_invariant_suite();
|
|
||||||
sr = srunner_create(s);
|
|
||||||
|
|
||||||
srunner_run_all(sr, CK_NORMAL);
|
|
||||||
number_failed = srunner_ntests_failed(sr);
|
|
||||||
srunner_free(sr);
|
|
||||||
|
|
||||||
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
@@ -95,6 +95,9 @@
|
|||||||
},
|
},
|
||||||
"overlay-ports": [
|
"overlay-ports": [
|
||||||
"./res/vcpkg"
|
"./res/vcpkg"
|
||||||
|
],
|
||||||
|
"overlay-triplets": [
|
||||||
|
"./res/vcpkg-triplets"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"overrides": [
|
"overrides": [
|
||||||
|
|||||||
Reference in New Issue
Block a user