Skip to content

Commit b79cce5

Browse files
committed
fix: auto-disable XDP for non-conforming apps
Disable XDP integration when the appid does not conform xdp id Signed-off-by: reddevillg <reddevillg@gmail.com>
1 parent 235d593 commit b79cce5

5 files changed

Lines changed: 166 additions & 0 deletions

File tree

libs/linglong/src/linglong/cli/cli.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
#include "linglong/utils/namespace.h"
4444
#include "linglong/utils/runtime_config.h"
4545
#include "linglong/utils/xdg/directory.h"
46+
#include "linglong/utils/xdp.h"
4647
#include "ocppi/runtime/ExecOption.hpp"
4748
#include "ocppi/runtime/RunOption.hpp"
4849
#include "ocppi/runtime/Signal.hpp"
@@ -867,6 +868,14 @@ int Cli::runResolvedContext(runtime::RunContext &runContext,
867868
return -1;
868869
}
869870

871+
const auto &appid = runContext.getTargetID();
872+
if (!options.disableXdp.has_value() && !utils::isValidXdgDesktopPortalId(appid)) {
873+
LogW("appid '{}' doesn't conform to XDP ID specification, disabling XDP integration. "
874+
"Use --enable-xdp to override.",
875+
appid);
876+
runOptions.disableXdp = true;
877+
}
878+
870879
auto container = this->containerBuilder.createRunContainer(runContext, runOptions);
871880
if (!container) {
872881
this->printer.printErr(container.error());

libs/linglong/tests/ll-tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ pfl_add_executable(
6464
src/linglong/utils/sha256_test.cpp
6565
src/linglong/utils/transaction_test.cpp
6666
src/linglong/utils/xdg/directory_test.cpp
67+
src/linglong/utils/xdp_test.cpp
6768
src/main.cpp
6869

6970

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
3+
*
4+
* SPDX-License-Identifier: LGPL-3.0-or-later
5+
*/
6+
7+
#include <gtest/gtest.h>
8+
9+
#include "linglong/utils/xdp.h"
10+
11+
using namespace linglong::utils;
12+
13+
TEST(IsValidXdgDesktopPortalIdTest, ValidStandardId)
14+
{
15+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example.app"));
16+
EXPECT_TRUE(isValidXdgDesktopPortalId("com.deepin.calculator"));
17+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.freedesktop.portal"));
18+
}
19+
20+
TEST(IsValidXdgDesktopPortalIdTest, ValidWithHyphenInLastSegment)
21+
{
22+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example.my-app"));
23+
EXPECT_TRUE(isValidXdgDesktopPortalId("com.deepin.app-launcher"));
24+
}
25+
26+
TEST(IsValidXdgDesktopPortalIdTest, ValidWithUnderscore)
27+
{
28+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example_my.app"));
29+
EXPECT_TRUE(isValidXdgDesktopPortalId("com.deepin.my_app"));
30+
}
31+
32+
TEST(IsValidXdgDesktopPortalIdTest, ValidWithDigits)
33+
{
34+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example.app2"));
35+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.2example.app"));
36+
}
37+
38+
TEST(IsValidXdgDesktopPortalIdTest, ValidMultiSegment)
39+
{
40+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.deepin.linglong.app"));
41+
EXPECT_TRUE(isValidXdgDesktopPortalId("a.b.c.d.e"));
42+
}
43+
44+
TEST(IsValidXdgDesktopPortalIdTest, InvalidSingleSegment)
45+
{
46+
EXPECT_FALSE(isValidXdgDesktopPortalId("single"));
47+
EXPECT_FALSE(isValidXdgDesktopPortalId("app"));
48+
}
49+
50+
TEST(IsValidXdgDesktopPortalIdTest, InvalidEmptyString)
51+
{
52+
EXPECT_FALSE(isValidXdgDesktopPortalId(""));
53+
}
54+
55+
TEST(IsValidXdgDesktopPortalIdTest, InvalidHyphenInNonLastSegment)
56+
{
57+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.my-app.app"));
58+
EXPECT_FALSE(isValidXdgDesktopPortalId("my-org.example.app"));
59+
}
60+
61+
TEST(IsValidXdgDesktopPortalIdTest, InvalidEmptySegment)
62+
{
63+
EXPECT_FALSE(isValidXdgDesktopPortalId("org..app"));
64+
EXPECT_FALSE(isValidXdgDesktopPortalId(".org.app"));
65+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.app."));
66+
}
67+
68+
TEST(IsValidXdgDesktopPortalIdTest, InvalidSpecialChars)
69+
{
70+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.example.app!"));
71+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.example.app@home"));
72+
EXPECT_FALSE(isValidXdgDesktopPortalId("org/example/app"));
73+
}
74+
75+
TEST(IsValidXdgDesktopPortalIdTest, InvalidSlashInId)
76+
{
77+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.deepin.calculator/stable"));
78+
EXPECT_FALSE(isValidXdgDesktopPortalId("org/deepin/app"));
79+
}
80+
81+
TEST(IsValidXdgDesktopPortalIdTest, InvalidHyphenInMultipleNonLastSegments)
82+
{
83+
EXPECT_FALSE(isValidXdgDesktopPortalId("my-org.my-app.app"));
84+
}
85+
86+
TEST(IsValidXdgDesktopPortalIdTest, ValidHyphenOnlyInLastSegment)
87+
{
88+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example.a-b"));
89+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.example.a-b-c"));
90+
}
91+
92+
TEST(IsValidXdgDesktopPortalIdTest, InvalidLastSegmentEmpty)
93+
{
94+
EXPECT_FALSE(isValidXdgDesktopPortalId("org.example."));
95+
}
96+
97+
TEST(IsValidXdgDesktopPortalIdTest, TwoSegmentsValid)
98+
{
99+
EXPECT_TRUE(isValidXdgDesktopPortalId("org.app"));
100+
EXPECT_TRUE(isValidXdgDesktopPortalId("a.b"));
101+
}

libs/utils/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ pfl_add_library(
4848
src/linglong/utils/transaction.h
4949
src/linglong/utils/xdg/directory.cpp
5050
src/linglong/utils/xdg/directory.h
51+
src/linglong/utils/xdp.h
5152
COMPILE_FEATURES
5253
PUBLIC
5354
cxx_std_17
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
3+
*
4+
* SPDX-License-Identifier: LGPL-3.0-or-later
5+
*/
6+
7+
#pragma once
8+
9+
#include <algorithm>
10+
#include <cctype>
11+
#include <string>
12+
#include <vector>
13+
14+
namespace linglong::utils {
15+
16+
inline bool isValidXdgDesktopPortalId(const std::string &appid) noexcept
17+
{
18+
std::vector<std::string> segments;
19+
std::string seg;
20+
for (char c : appid) {
21+
if (c == '.') {
22+
segments.push_back(std::move(seg));
23+
seg.clear();
24+
} else {
25+
seg.push_back(c);
26+
}
27+
}
28+
segments.push_back(std::move(seg));
29+
30+
if (segments.size() < 2) {
31+
return false;
32+
}
33+
34+
for (size_t i = 0; i + 1 < segments.size(); ++i) {
35+
if (segments[i].empty()) {
36+
return false;
37+
}
38+
if (!std::all_of(segments[i].begin(), segments[i].end(), [](char c) {
39+
return std::isalnum(c) || c == '_';
40+
})) {
41+
return false;
42+
}
43+
}
44+
45+
const auto &last = segments.back();
46+
if (last.empty()) {
47+
return false;
48+
}
49+
return std::all_of(last.begin(), last.end(), [](char c) {
50+
return std::isalnum(c) || c == '_' || c == '-';
51+
});
52+
}
53+
54+
} // namespace linglong::utils

0 commit comments

Comments
 (0)