1#include "mtxclient/utils.hpp"
2
3#include <algorithm>
4#include <cstdint>
5#include <iomanip>
6#include <random>
7#include <sstream>
8#include <string>
9#include <utility>
10
11mtx::client::utils::MxcUrl
12mtx::client::utils::parse_mxc_url(const std::string &url)
13{
14 constexpr auto mxc_uri_protocol = "mxc://";
15 MxcUrl res;
16
17 if (url.find(s: mxc_uri_protocol) != 0)
18 return res;
19
20 auto str_left = url.substr(pos: 6);
21
22 std::vector<std::string> parts;
23
24 size_t pos = 0;
25 while ((pos = str_left.find(c: '/')) != std::string_view::npos) {
26 parts.push_back(x: std::string(str_left.substr(pos: 0, n: pos)));
27 str_left = str_left.substr(pos: pos + 1);
28 }
29 parts.emplace_back(args&: str_left);
30
31 if (parts.size() != 2) {
32 res.server = parts.at(n: 0);
33 return res;
34 }
35
36 res.server = parts.at(n: 0);
37 res.media_id = parts.at(n: 1);
38
39 return res;
40}
41
42bool
43mtx::client::utils::is_number(const std::string &s)
44{
45 return !s.empty() &&
46 std::find_if(first: s.begin(), last: s.end(), pred: [](char c) { return !std::isdigit(c); }) == s.end();
47}
48
49std::string
50mtx::client::utils::random_token(uint8_t len, bool with_symbols) noexcept
51{
52 std::string symbols = "!@#$%^&*()";
53 std::string alphanumberic("abcdefghijklmnopqrstuvwxyz"
54 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
55 "1234567890");
56
57 const auto chars = with_symbols ? alphanumberic + symbols : alphanumberic;
58
59 thread_local std::random_device rng;
60 std::uniform_int_distribution<> index_dist(0, (int)chars.size() - 1);
61
62 std::string token;
63 token.reserve(res: len);
64
65 for (uint8_t i = 0; i < len; ++i)
66 token.push_back(c: chars[index_dist(rng)]);
67
68 return token;
69}
70
71std::string
72mtx::client::utils::query_params(const std::map<std::string, std::string> &params) noexcept
73{
74 if (params.empty())
75 return "";
76
77 auto pb = params.cbegin();
78 auto pe = params.cend();
79
80 std::string data = pb->first + "=" + url_encode(s: pb->second);
81 ++pb;
82
83 if (pb == pe)
84 return data;
85
86 for (; pb != pe; ++pb)
87 data += "&" + pb->first + "=" + url_encode(s: pb->second);
88
89 return data;
90}
91
92std::string
93mtx::client::utils::url_encode(const std::string &value) noexcept
94{
95 // https: // stackoverflow.com/questions/154536/encode-decode-urls-in-c
96 std::ostringstream escaped;
97 escaped.fill(ch: '0');
98 escaped << std::hex;
99
100 for (char c : value) {
101 // Keep alphanumeric and other accepted characters intact
102 if (std::isalnum(c) || c == '-' || c == '_' || c == '.' || c == '~') {
103 escaped << c;
104 continue;
105 }
106
107 // Any other characters are percent-encoded
108 escaped << std::uppercase;
109 escaped << '%' << std::setw(2) << int((unsigned char)c);
110 escaped << std::nouppercase;
111 }
112
113 return escaped.str();
114}
115