FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
webview_impl.cpp
1
20#include <webview.h>
21
22#include "webview_impl.hpp"
23#include <algorithm>
24#include <cassert>
25#include <cctype>
26#include <map>
27#include <regex>
28#include <sstream>
29#include <string>
30#include <vector>
31
32#include <freerdp/log.h>
33#include <winpr/string.h>
34
35#define TAG FREERDP_TAG("client.SDL.common.aad")
36
37class fkt_arg
38{
39 public:
40 fkt_arg(const std::string& url)
41 {
42 auto args = urlsplit(url);
43 auto redir = args.find("redirect_uri");
44 if (redir == args.end())
45 {
46 WLog_ERR(TAG,
47 "[Webview] url %s does not contain a redirect_uri parameter, "
48 "aborting.",
49 url.c_str());
50 }
51 else
52 {
53 _redirect_uri = from_url_encoded_str(redir->second);
54 }
55 }
56
57 bool valid() const
58 {
59 return !_redirect_uri.empty();
60 }
61
62 bool getCode(std::string& c) const
63 {
64 c = _code;
65 return !c.empty();
66 }
67
68 bool handle(const std::string& uri) const
69 {
70 std::string duri = from_url_encoded_str(uri);
71 if (duri.length() < _redirect_uri.length())
72 return false;
73 auto rc = _strnicmp(duri.c_str(), _redirect_uri.c_str(), _redirect_uri.length());
74 return rc == 0;
75 }
76
77 bool parse(const std::string& uri)
78 {
79 _args = urlsplit(uri);
80 auto err = _args.find("error");
81 if (err != _args.end())
82 {
83 auto suberr = _args.find("error_subcode");
84 WLog_ERR(TAG, "[Webview] %s: %s, %s: %s", err->first.c_str(), err->second.c_str(),
85 suberr->first.c_str(), suberr->second.c_str());
86 return false;
87 }
88 auto val = _args.find("code");
89 if (val == _args.end())
90 {
91 WLog_ERR(TAG, "[Webview] no code parameter detected in redirect URI %s", uri.c_str());
92 return false;
93 }
94
95 _code = val->second;
96 return true;
97 }
98
99 protected:
100 static std::string from_url_encoded_str(const std::string& str)
101 {
102 std::string cxxstr;
103 auto cstr = winpr_str_url_decode(str.c_str(), str.length());
104 if (cstr)
105 {
106 cxxstr = std::string(cstr);
107 free(cstr);
108 }
109 return cxxstr;
110 }
111
112 static std::vector<std::string> split(const std::string& input, const std::string& regex)
113 {
114 // passing -1 as the submatch index parameter performs splitting
115 std::regex re(regex);
116 std::sregex_token_iterator first{ input.begin(), input.end(), re, -1 };
117 std::sregex_token_iterator last;
118 return { first, last };
119 }
120
121 static std::map<std::string, std::string> urlsplit(const std::string& url)
122 {
123 auto pos = url.find('?');
124 if (pos == std::string::npos)
125 return {};
126
127 pos++; // skip '?'
128 auto surl = url.substr(pos);
129 auto args = split(surl, "&");
130
131 std::map<std::string, std::string> argmap;
132 for (const auto& arg : args)
133 {
134 auto kv = split(arg, "=");
135 if (kv.size() == 2)
136 argmap.insert({ kv[0], kv[1] });
137 }
138
139 return argmap;
140 }
141
142 private:
143 std::string _redirect_uri;
144 std::string _code;
145 std::map<std::string, std::string> _args;
146};
147
148static void fkt(webview_t webview, const char* uri, webview_navigation_event_t type, void* arg)
149{
150 assert(arg);
151 auto rcode = static_cast<fkt_arg*>(arg);
152
153 if (type != WEBVIEW_LOAD_FINISHED)
154 return;
155
156 if (!rcode->handle(uri))
157 return;
158
159 (void)rcode->parse(uri);
160 webview_terminate(webview);
161}
162
163bool webview_impl_run(const std::string& title, const std::string& url, std::string& code)
164{
165 webview::webview w(false, nullptr);
166
167 w.set_title(title);
168 w.set_size(800, 600, WEBVIEW_HINT_NONE);
169
170 fkt_arg arg(url);
171 if (!arg.valid())
172 {
173 return false;
174 }
175 w.add_navigation_listener(fkt, &arg);
176 w.navigate(url);
177 w.run();
178 return arg.getCode(code);
179}