-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
cockpit-desktop.in
155 lines (134 loc) · 5.11 KB
/
cockpit-desktop.in
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#!/bin/bash
# This file is part of Cockpit.
#
# Copyright (C) 2018 Red Hat, Inc.
#
# Cockpit is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation; either version 2.1 of the License, or
# (at your option) any later version.
#
# Cockpit is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Cockpit; If not, see <https://www.gnu.org/licenses/>.
# Run a local bridge, web server, and browser for a particular Cockpit page.
# This is useful for integration into .desktop files, for systems which don't
# have cockpit.socket enabled. The web server and browser run in an unshared
# network namespace, and thus are totally isolated from everything else.
#
# Examples:
# cockpit-desktop /cockpit/@localhost/system/index.html
# cockpit-desktop network/firewall
# cockpit-desktop users
#
# As an experimental/demo feature, the bridge can also be started on a remote
# ssh host. The host name is given as (optional) second argument, which is
# passed verbatim to ssh.
#
# Example:
# cockpit-desktop system svr1
# cockpit-desktop / username@svr1
set -eu
# exec_prefix= is set because the default @libexecdir@ contains "${exec_prefix}"
exec_prefix="@prefix@"
libexecdir="@libexecdir@"
# start browser in a temporary home dir, so that it does not interfere with your real one
BROWSER_HOME=$(mktemp --directory --tmpdir cockpit.desktop.XXXXXX)
export BROWSER_HOME
# find suitable browser, unless already set by $BROWSER
# We can't use xdg-open, it does too much magic behind the back to connect to
# existing instances (outside of our namespace) and does not allow us to reduce
# the UI, or pass options like chromium's --no-sandbox.
detect_browser()
{
[ -z "${BROWSER:-}" ] || return 0
# First choice, but it depends on gi.repository WebKit2, so check it
if @libexecdir@/cockpit-client --help >/dev/null 2>/dev/null; then
BROWSER="@libexecdir@/cockpit-client --disable-uniqueness --no-ui --external-ws"
return 0
fi
for browser in chromium-browser chromium google-chrome; do
if type $browser >/dev/null 2>&1; then
# need to disable sandboxing in user namespace, but that already isolates
# TODO: Find a way to disable the URL bar
BROWSER="$browser --no-sandbox --disable-infobars"
return 0
fi
done
# create firefox profile
FIREFOX_PROFILE="$BROWSER_HOME/profile"
mkdir "$FIREFOX_PROFILE"
cat <<EOF > "$FIREFOX_PROFILE/user.js"
user_pref("datareporting.policy.dataSubmissionEnabled", false);
user_pref("toolkit.telemetry.reportingpolicy.firstRun", false);
user_pref("browser.toolbars.bookmarks.visibility", "never");
EOF
if type firefox >/dev/null 2>&1; then
# TODO: Find a way to disable the URL bar
BROWSER="firefox --profile $FIREFOX_PROFILE --no-remote"
return 0
fi
for id in org.mozilla.firefox org.mozilla.Firefox; do
if flatpak info $id >/dev/null 2>&1; then
BROWSER="flatpak run --filesystem=$BROWSER_HOME $id --profile $FIREFOX_PROFILE --no-remote"
return 0
fi
done
# TODO: is there a simple way to use webkitgtk?
echo "No suitable browser found (Chromium/Chrome, or Firefox)" >&2
exit 1
}
if [ -z "${1:-}" ]; then
echo "Usage: $0 <Cockpit path> [ssh host]" >&2
exit 1
fi
# Expand the commandline argument into a url
case "$1" in
/*)
URL_PATH="$1"
;;
*/)
URL_PATH="/cockpit/@localhost/$1index.html"
;;
*/*)
URL_PATH="/cockpit/@localhost/$1.html"
;;
*)
URL_PATH="/cockpit/@localhost/$1/index.html"
;;
esac
detect_browser
# start the bridge; this needs to run in the normal user session/namespace
coproc ${2:+ssh "$2"} cockpit-bridge
trap "kill $COPROC_PID; wait $COPROC_PID || true" EXIT INT QUIT PIPE
# start ws and browser in a detached network namespace
SCRIPT='
set -eu
# new namespaces have lo down by default
ip link set lo up >&2
# forward parent stdin and stdout (from bridge) to cockpit-ws
# it pretty well does not matter which port we use in our own namespace, so use standard http
# disable /etc/cockpit/
XDG_CONFIG_DIRS="$BROWSER_HOME" COCKPIT_SUPERUSER="pkexec" '${COCKPIT_WS:-@libexecdir@/cockpit-ws}' -p 80 -a 127.0.0.90 --local-session=- <&0 >&1 &
WS_PID=$!
# ... and stop using that stdin/out for everything else
exec 0</dev/null
exec 1>&2
trap "set +e; kill $WS_PID; wait $WS_PID; rm -rf $BROWSER_HOME" EXIT INT QUIT PIPE
# if we have netcat, use it for waiting until ws is up
if type nc >/dev/null 2>&1; then
for retry in `seq 10`; do
nc -z 127.0.0.90 80 && break
sleep 0.5;
done
else
# otherwise, just wait a bit
sleep 3
fi
HOME="$BROWSER_HOME" '$BROWSER' http://127.0.0.90'"$URL_PATH"'
'
unshare --user --map-root-user --net /bin/bash -c "$SCRIPT" <&${COPROC[0]} >&${COPROC[1]}