· 4 years ago · Aug 14, 2021, 12:06 AM
1#include <fstream>
2#include <iostream>
3#include <optional>
4#include <string>
5#include <variant>
6#include <vector>
7
8struct AcmeConfig {
9 bool setup;
10 std::string key, certificate, fullchain;
11 std::optional<std::vector<std::string>> alt_names;
12};
13
14struct Certificate {
15 std::string key, cert;
16};
17
18struct Domain {
19 std::string domain;
20 std::string document_root;
21 std::optional<AcmeConfig> acme;
22 std::optional<std::variant<std::reference_wrapper<AcmeConfig>, Certificate>>
23 tls;
24 std::optional<std::string> redirect;
25
26 std::optional<Certificate> get_cert() noexcept {
27 if (!tls)
28 return std::nullopt;
29 Certificate cert;
30 try {
31 AcmeConfig acme =
32 std::get<std::reference_wrapper<AcmeConfig>>(tls.value()).get();
33 cert.key = acme.key;
34 cert.cert = acme.fullchain;
35 } catch (const std::bad_variant_access &ex) {
36 return (std::get<Certificate>(tls.value()));
37 }
38 return cert;
39 }
40
41 void get_httpd_conf(std::ostream &out = std::cout) {
42 out << "server \"" << domain << "\" {\n";
43
44 if (tls) {
45 Certificate cert =
46 get_cert()
47 .value(); /* should always exist since we're within TLS context */
48
49 if (acme && !acme.value().setup) {
50 out << " listen on * port 80\n"
51 << " root \"" << document_root << "\"\n"
52 << " location \"/.well-known/acme-challenge/*\" {\n"
53 << " root \"/acme\"\n"
54 << " request strip 2\n"
55 << " }\n";
56 } else {
57 out << " listen on * tls port 443\n";
58 if (redirect) {
59 out << " block return 301 \"" << redirect.value() << "\"\n";
60 }
61 out << " root \"" << document_root << "\"\n"
62 << " tls {\n"
63 << " certificate \"" << cert.cert << "\"\n"
64 << " key \"" << cert.key << "\"\n"
65 << " }\n"
66 << " location \"/.well-known/acme-challenge/*\" {\n"
67 << " root \"/acme\"\n"
68 << " request strip 2\n"
69 << " }\n}\n"
70 << "server \"" << domain << "\" {\n"
71 << " listen on * port 80\n"
72 << " block return 301 \"https://" << domain << "$REQUEST_URI\"\n";
73 }
74 } else {
75 out << " listen on * port 80\n"
76 << " root \"" << document_root << "\"\n";
77 }
78
79 out << "}\n" << std::endl;
80 }
81
82 static void get_acme_preamble(std::ostream &out = std::cout) {
83 out << "authority letsencrypt {\n"
84 << " api url \"https://acme-v02.api.letsencrypt.org/directory\"\n"
85 << " account key \"/etc/ssl/private/letsencrypt.key\"\n"
86 << "}\n"
87 << std::endl;
88 }
89
90 void get_acme_conf(std::ostream &out = std::cout) {
91 if (!this->acme)
92 return;
93 AcmeConfig acme = this->acme.value();
94
95 out << "domain " << domain << " {\n";
96 if (acme.alt_names) {
97 out << " alternative names { ";
98 std::for_each(acme.alt_names.value().begin(),
99 acme.alt_names.value().end(),
100 [&out](const std::string n) { out << n << " "; });
101 out << "}\n";
102 }
103 out << " domain key \"" << acme.key << "\"\n"
104 << " domain certificate \"" << acme.certificate << "\"\n"
105 << " domain full chain certificate \"" << acme.fullchain << "\"\n"
106 << " sign with letsencrypt\n"
107 << "}\n"
108 << std::endl;
109 }
110};
111
112namespace Parser {
113std::optional<Domain> get_domain(std::istream &in) {
114 Domain domain = {};
115 std::string tmp;
116 in >> tmp;
117 if (tmp != "domain")
118 return std::nullopt;
119
120 std::cout << tmp << std::endl;
121
122 return domain;
123}
124}; // namespace Parser
125
126namespace Action {
127 void execute(std::vector<Domain> &dom) {}
128}; // namespace Action
129
130int main() {
131 std::ifstream fs;
132 fs.open("gen_httpd.conf");
133
134 std::optional<Domain> dom = Parser::get_domain(fs);
135 if (dom) {
136 std::cout << "found a domain!" << std::endl;
137 } else {
138 std::cout << "no domain :(" << std::endl;
139 }
140
141 return 0;
142}