Anklang 0.3.0-460-gc4ef46ba
ASE — Anklang Sound Engine (C++)

« « « Anklang Documentation
Loading...
Searching...
No Matches
webui.cc
Go to the documentation of this file.
1 // This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
2#include "webui.hh"
3#include "atquit.hh"
4#include "platform.hh"
5#include "strings.hh"
6#include <cerrno>
7#include <sys/wait.h>
8#include <sys/prctl.h>
9#include <sys/stat.h>
10#include <filesystem>
11#include <dirent.h>
12#include "path.hh"
13
14#define WDEBUG(...) Ase::debug ("webui", __VA_ARGS__)
15
16namespace Ase {
17
18String // check errno
19webui_create_auth_redirect (const std::string &executable, unsigned port, const std::string &token, const std::string &snapmode)
20{
21 String basedir = Path::cache_home() + "/" + executable;
22 /* The canonical path for the redirect is $XDG_CACHE_HOME/<executable>/<executable>-<port>.html
23 * But snap based browsers cannot read from ~/.* $XDG_RUNTIME_DIR ~/snap/… /var/tmp or /tmp/.
24 * This means we must find a path under ~/[^.]* or ~/<subdir>/.something that comes close.
25 * In any case, we only do this on systems with snapd.
26 */
27 bool snap_workaround = true; // __linux__
28 if (!Path::check ("/tmp/snap-private-tmp/", "d") ||
29 (snapmode == "htmlgui" && Path::check (anklang_runpath (RPath::ELECTRONDIR, "htmlgui"), "x")))
30 snap_workaround = false; // not starting a snap browser
31 if (snap_workaround) {
32 basedir = Path::xdg_dir ("DOWNLOAD") + "/." + executable;
33 const auto readme =
34 "This directory only exists to enable temporary file exchange with\n"
35 "snap packages which are unable to read from ~/.cache/.\n"
36 "Feel free to remove this directory in its entirety.\n";
37 if (!Path::check (basedir, "dw") &&
38 !Path::stringwrite (basedir + "/README", readme, true)) {
39 errno = errno ? errno : EIO;
40 return basedir;
41 }
42 }
44 const String link = string_format ("http://localhost:%u/~auth", port);
45 const String query = token.empty() ? "" : "?token=" + token;
46 const String ua = string_format ("%s-%u", string_capitalize (executable), port);
47 const String html_text =
48 string_format ("<!DOCTYPE html>\n"
49 "<html><!--@@TEMPFILE_PID=%d@@-->\n"
50 "<head><title>%s Authentication Redirect</title>\n" // 307 Temporary Redirect
51 "<meta http-equiv=\"refresh\" content=\"0; url=%s\">\n"
52 "</head>\n<body>\n"
53 "<h1>%s Authentication Redirect</h1>\n\n"
54 "<p>Redirecting to %s: <a href=\"%s\">%s</a></p>\n"
55 "<hr><address>%s</address>\n"
56 "<hr></body></html>\n",
57 getpid(), ua, link + query, ua, ua, link + query, link, ua);
58 const String html_file = string_format ("%s/%s-%u.html", basedir, executable, port);
59 if (!Path::stringwrite (html_file, html_text, true, 0600))
60 errno = errno ? errno : EIO;
61 else {
62 atquit_add_removal (html_file);
63 errno = 0;
64 }
65 return html_file;
66}
67
68ErrorReason
69webui_start_browser (const std::string &mode, MainLoopP loop, const std::string &url, const std::function<void()> &onclose)
70{
72 std::string browser_name;
73
74 if (mode == "chromium" || mode == "google-chrome")
75 {
76 browser_name = mode;
77 argv.push_back (browser_name);
79 if (temp_dir.empty())
80 return { errno, "mkdtemp" };
81 const std::string user_data_dir_arg = "--user-data-dir=" + temp_dir;
82 std::string app = "--app=";
83 app += url;
84 for (const auto arg : {
85 "--incognito", "--no-first-run", "--no-experiments",
86 "--no-default-browser-check", "--disable-extensions", "--disable-sync",
87 // "--auto-open-devtools-for-tabs",
88 "--bwsi", "--new-window" })
89 argv.push_back (arg);
90 argv.push_back (user_data_dir_arg);
91 argv.push_back (app);
92 }
93 else if (mode == "htmlgui")
94 {
95 browser_name = mode;
96 argv.push_back (anklang_runpath (RPath::ELECTRONDIR, "htmlgui"));
97 argv.push_back ("--no-sandbox");
98 argv.push_back (url);
99 }
100 else if (mode == "none" or mode == "" or mode == "wait")
101 return { 0 }; // none
102 else
103 return { EINVAL, string_format ("unknown webui: %s", mode) };
104
105 pid_t child_pid = 0;
106 ErrorReason ereason = spawn_process (argv, &child_pid, SIGTERM);
107 if (ereason.error)
108 return ereason;
109 atquit_add_killl_pid (child_pid);
110 loop->exec_sigchld (child_pid,
111 [onclose] (pid_t pid, int status)
112 {
113 std::string state;
114 if (WIFEXITED (status))
115 state = string_format ("status=%d", WEXITSTATUS (status));
116 else if (WIFSIGNALED (status))
117 state = string_format ("signal=%d", WTERMSIG (status));
118 if (state.size()) {
119 log ("WebUI: child process pid=%d exited: %s", pid, state);
120 atquit_del_killl_pid (pid);
121 }
122 if (onclose)
123 onclose();
124 });
125 log ("WebUI: started %s pid=%d: %s", browser_name, child_pid, url);
126 return { 0, "" }; // Success
127}
128
129} // Ase
#define EIO
T empty(T... args)
errno
getpid
link
log
bool check(const String &file, const String &mode)
Definition path.cc:625
String cache_home()
Get the $XDG_CACHE_HOME directory, see: https://specifications.freedesktop.org/basedir-spec/latest.
Definition path.cc:322
The Anklang C++ API namespace.
Definition api.hh:9
std::string string_format(const char *format, const Args &...args) __attribute__((__format__(__printf__
Format a string similar to sprintf(3) with support for std::string and std::ostringstream convertible...
void atquit_add_removal(const std::string &filename)
Remove filename (or directory) when the program terminates.
Definition atquit.cc:106
ErrorReason spawn_process(const std::vector< std::string > &argv, pid_t *child_pid, int pdeathsig)
Span a child process after cleaning up the environment.
Definition atquit.cc:179
String string_capitalize(const String &str, size_t maxn, bool rest_tolower)
Capitalize words, so the first letter is upper case, the rest lower case.
Definition strings.cc:186
std::string anklang_runpath(RPath rpath, const String &segment)
Retrieve various resource paths at runtime.
Definition platform.cc:58
std::string String
Convenience alias for std::string.
Definition cxxaux.hh:35
void cleanup_orphaned_tempfiles(const std::string &directory)
Delete all files that contain @TEMPFILE_PID=d@ without a running pid_t d.
Definition atquit.cc:20
void atquit_add_killl_pid(int pid)
Kill pid when the program terminates.
Definition atquit.cc:165
std::string create_tempfile_dir(const std::string &basename)
Create temporary directory under /tmp, scheduled for removal atquit.
Definition atquit.cc:233
T size(T... args)
typedef pid_t