afterpresets 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/native-runtime/CMakeLists.txt +82 -0
- package/native-runtime/README.md +40 -0
- package/native-runtime/THIRD_PARTY_NOTICES.md +14 -0
- package/native-runtime/include/ap_native.h +223 -0
- package/native-runtime/src/apply.cpp +199 -0
- package/native-runtime/src/crypto.cpp +225 -0
- package/native-runtime/src/crypto.hpp +51 -0
- package/native-runtime/src/dialog.cpp +62 -0
- package/native-runtime/src/dialog.hpp +35 -0
- package/native-runtime/src/engine.cpp +909 -0
- package/native-runtime/src/engine.hpp +232 -0
- package/native-runtime/src/fsutil.cpp +291 -0
- package/native-runtime/src/fsutil.hpp +57 -0
- package/native-runtime/src/json.cpp +326 -0
- package/native-runtime/src/json.hpp +70 -0
- package/native-runtime/src/platform.hpp +83 -0
- package/native-runtime/src/platform_common.cpp +60 -0
- package/native-runtime/src/platform_mac.mm +314 -0
- package/native-runtime/src/platform_win.cpp +277 -0
- package/native-runtime/src/runtime.cpp +473 -0
- package/native-runtime/src/util.cpp +169 -0
- package/native-runtime/src/util.hpp +32 -0
- package/native-runtime/src/zip.cpp +243 -0
- package/native-runtime/src/zip.hpp +58 -0
- package/native-runtime/third_party/monocypher/LICENCE.md +167 -0
- package/native-runtime/third_party/monocypher/monocypher-ed25519.c +500 -0
- package/native-runtime/third_party/monocypher/monocypher-ed25519.h +140 -0
- package/native-runtime/third_party/monocypher/monocypher.c +2956 -0
- package/native-runtime/third_party/monocypher/monocypher.h +321 -0
- package/native-runtime/third_party/tinf/LICENSE +22 -0
- package/native-runtime/third_party/tinf/crc32.c +57 -0
- package/native-runtime/third_party/tinf/tinf.h +140 -0
- package/native-runtime/third_party/tinf/tinflate.c +636 -0
- package/native-runtime/vendor-files.json +39 -0
- package/package.json +6 -3
- package/runtime/docs/cep/host.md +8 -0
- package/runtime/docs/common/README.md +1 -1
- package/runtime/docs/native/README.md +44 -0
- package/runtime/docs/native/debugging.md +140 -0
- package/runtime/docs/native/rules.md +402 -0
- package/runtime/docs/native/testing.md +154 -0
- package/runtime/package.json +1 -1
- package/runtime/scripts/ae-sdk-docs/config.js +102 -0
- package/runtime/scripts/ae-sdk-docs/convert.js +430 -0
- package/runtime/scripts/ae-sdk-docs/index.js +314 -0
- package/runtime/scripts/ae-sdk-docs/source.js +205 -0
- package/runtime/scripts/ae-sdk-docs/split.js +170 -0
- package/runtime/scripts/ae-sdk-docs.js +72 -0
- package/runtime/src/host.js +1 -1
- package/src/api/error-messages.js +1 -1
- package/src/check/check.js +3 -3
- package/src/check/native.js +14 -0
- package/src/check/pricing.js +1 -1
- package/src/cli.js +2 -2
- package/src/commands/build.js +8 -2
- package/src/commands/check.js +10 -2
- package/src/commands/dev.js +9 -2
- package/src/commands/docs.js +5 -1
- package/src/commands/init.js +10 -7
- package/src/commands/push.js +5 -2
- package/src/commands/sdk.js +14 -0
- package/src/commands/testers.js +1 -1
- package/src/commands/upgrade.js +2 -2
- package/src/commands/whoami.js +1 -1
- package/src/dev/bridge.js +8 -0
- package/src/dev/native.js +3 -0
- package/src/dev/session.js +4 -3
- package/src/mcp/extendscript.js +9 -8
- package/src/mcp/host-target.js +1 -0
- package/src/mcp/panels.js +1 -1
- package/src/mcp/png.js +1 -0
- package/src/mcp/server.js +2 -2
- package/src/mcp/tools/capture.js +3 -0
- package/src/mcp/tools/host.js +1 -1
- package/src/mcp/tools/native.js +6 -0
- package/src/mcp/tools/project.js +48 -32
- package/src/mcp/tools/releases.js +23 -20
- package/src/native/build.js +27 -0
- package/src/native/cmake/CMakeLists.txt +88 -0
- package/src/native/cmake/zig-windows.cmake +19 -0
- package/src/native/effect.js +3 -0
- package/src/native/install.js +8 -0
- package/src/native/installers.js +4 -0
- package/src/native/pipl.js +20 -0
- package/src/native/restart.js +2 -0
- package/src/native/sdk.js +8 -0
- package/src/project/docs.js +3 -3
- package/src/project/project.js +2 -2
- package/src/project/template.js +5 -4
- package/src/prompt.js +1 -1
- package/src/release/native.js +3 -0
- package/src/release/publish.js +1 -1
- package/src/system/run-command.js +1 -1
- package/src/targets.js +1 -1
- package/template/cep/AGENTS.md +99 -164
- package/template/cep/README.md +7 -2
- package/template/cep/docs/code_guide.md +67 -0
- package/template/cep/docs/initial_setup.md +58 -12
- package/template/cep/docs/release_checklist.md +24 -0
- package/template/hosts/AGENTS.two-apps.md +12 -0
- package/template/native/.mcp.json +8 -0
- package/template/native/AGENTS.md +105 -0
- package/template/native/README.md +71 -0
- package/template/native/docs/code_guide.md +72 -0
- package/template/native/docs/initial_setup.md +179 -0
- package/template/native/docs/release_checklist.md +24 -0
- package/template/native/effect.json +16 -0
- package/template/native/gitignore +8 -0
- package/template/native/package.json +14 -0
- package/template/native/src/Effect.cpp +224 -0
- package/template/native/src/License.cpp +95 -0
- package/template/native/src/License.h +29 -0
- package/template/native/src/Render.h +68 -0
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
#include "crypto.hpp"
|
|
2
|
+
|
|
3
|
+
#include <cstdio>
|
|
4
|
+
#include <cstring>
|
|
5
|
+
|
|
6
|
+
extern "C" {
|
|
7
|
+
#include "monocypher-ed25519.h"
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
namespace apn {
|
|
11
|
+
|
|
12
|
+
namespace {
|
|
13
|
+
|
|
14
|
+
constexpr uint32_t K[64] = {
|
|
15
|
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
|
16
|
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
|
17
|
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
|
18
|
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
|
19
|
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
|
20
|
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
|
21
|
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
|
22
|
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2};
|
|
23
|
+
|
|
24
|
+
inline uint32_t rotr(uint32_t x, int n) { return (x >> n) | (x << (32 - n)); }
|
|
25
|
+
|
|
26
|
+
// Ed25519 SubjectPublicKeyInfo prefix: SEQUENCE { SEQUENCE { OID 1.3.101.112 } BIT STRING (33) }.
|
|
27
|
+
constexpr uint8_t SPKI_PREFIX[12] = {0x30, 0x2a, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x03, 0x21, 0x00};
|
|
28
|
+
|
|
29
|
+
std::string trim(const std::string &s) {
|
|
30
|
+
size_t a = 0, b = s.size();
|
|
31
|
+
while (a < b && (s[a] == ' ' || s[a] == '\t' || s[a] == '\r' || s[a] == '\n')) a++;
|
|
32
|
+
while (b > a && (s[b - 1] == ' ' || s[b - 1] == '\t' || s[b - 1] == '\r' || s[b - 1] == '\n')) b--;
|
|
33
|
+
return s.substr(a, b - a);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
std::optional<PublicKey> key_from_der(const std::vector<uint8_t> &der) {
|
|
37
|
+
PublicKey key{};
|
|
38
|
+
if (der.size() == 32) {
|
|
39
|
+
std::memcpy(key.data(), der.data(), 32);
|
|
40
|
+
return key;
|
|
41
|
+
}
|
|
42
|
+
if (der.size() == 44 && std::memcmp(der.data(), SPKI_PREFIX, sizeof SPKI_PREFIX) == 0) {
|
|
43
|
+
std::memcpy(key.data(), der.data() + 12, 32);
|
|
44
|
+
return key;
|
|
45
|
+
}
|
|
46
|
+
return std::nullopt;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
std::optional<PublicKey> key_from_pem(const std::string &pem) {
|
|
50
|
+
const std::string begin = "-----BEGIN PUBLIC KEY-----";
|
|
51
|
+
const std::string end = "-----END PUBLIC KEY-----";
|
|
52
|
+
size_t a = pem.find(begin);
|
|
53
|
+
size_t b = pem.find(end);
|
|
54
|
+
if (a == std::string::npos || b == std::string::npos || b < a) return std::nullopt;
|
|
55
|
+
auto der = base64_decode(pem.substr(a + begin.size(), b - a - begin.size()));
|
|
56
|
+
if (!der) return std::nullopt;
|
|
57
|
+
return key_from_der(*der);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
} // namespace
|
|
61
|
+
|
|
62
|
+
Sha256::Sha256() {
|
|
63
|
+
static constexpr uint32_t init[8] = {0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
|
64
|
+
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19};
|
|
65
|
+
std::memcpy(h_, init, sizeof h_);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
void Sha256::block(const uint8_t *p) {
|
|
69
|
+
uint32_t w[64];
|
|
70
|
+
for (int i = 0; i < 16; i++) {
|
|
71
|
+
w[i] = (uint32_t)p[i * 4] << 24 | (uint32_t)p[i * 4 + 1] << 16 | (uint32_t)p[i * 4 + 2] << 8 | p[i * 4 + 3];
|
|
72
|
+
}
|
|
73
|
+
for (int i = 16; i < 64; i++) {
|
|
74
|
+
uint32_t s0 = rotr(w[i - 15], 7) ^ rotr(w[i - 15], 18) ^ (w[i - 15] >> 3);
|
|
75
|
+
uint32_t s1 = rotr(w[i - 2], 17) ^ rotr(w[i - 2], 19) ^ (w[i - 2] >> 10);
|
|
76
|
+
w[i] = w[i - 16] + s0 + w[i - 7] + s1;
|
|
77
|
+
}
|
|
78
|
+
uint32_t a = h_[0], b = h_[1], c = h_[2], d = h_[3], e = h_[4], f = h_[5], g = h_[6], h = h_[7];
|
|
79
|
+
for (int i = 0; i < 64; i++) {
|
|
80
|
+
uint32_t S1 = rotr(e, 6) ^ rotr(e, 11) ^ rotr(e, 25);
|
|
81
|
+
uint32_t ch = (e & f) ^ (~e & g);
|
|
82
|
+
uint32_t t1 = h + S1 + ch + K[i] + w[i];
|
|
83
|
+
uint32_t S0 = rotr(a, 2) ^ rotr(a, 13) ^ rotr(a, 22);
|
|
84
|
+
uint32_t maj = (a & b) ^ (a & c) ^ (b & c);
|
|
85
|
+
uint32_t t2 = S0 + maj;
|
|
86
|
+
h = g; g = f; f = e; e = d + t1; d = c; c = b; b = a; a = t1 + t2;
|
|
87
|
+
}
|
|
88
|
+
h_[0] += a; h_[1] += b; h_[2] += c; h_[3] += d; h_[4] += e; h_[5] += f; h_[6] += g; h_[7] += h;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
void Sha256::update(const void *data, size_t size) {
|
|
92
|
+
const uint8_t *p = static_cast<const uint8_t *>(data);
|
|
93
|
+
total_ += size;
|
|
94
|
+
if (buf_len_) {
|
|
95
|
+
size_t take = 64 - buf_len_ < size ? 64 - buf_len_ : size;
|
|
96
|
+
std::memcpy(buf_ + buf_len_, p, take);
|
|
97
|
+
buf_len_ += take; p += take; size -= take;
|
|
98
|
+
if (buf_len_ == 64) { block(buf_); buf_len_ = 0; }
|
|
99
|
+
}
|
|
100
|
+
while (size >= 64) { block(p); p += 64; size -= 64; }
|
|
101
|
+
if (size) { std::memcpy(buf_, p, size); buf_len_ = size; }
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
std::array<uint8_t, 32> Sha256::digest() {
|
|
105
|
+
uint64_t bits = total_ * 8;
|
|
106
|
+
uint8_t pad = 0x80;
|
|
107
|
+
update(&pad, 1);
|
|
108
|
+
uint8_t zero = 0;
|
|
109
|
+
while (buf_len_ != 56) update(&zero, 1);
|
|
110
|
+
uint8_t len[8];
|
|
111
|
+
for (int i = 0; i < 8; i++) len[i] = (uint8_t)(bits >> (56 - 8 * i));
|
|
112
|
+
update(len, 8);
|
|
113
|
+
std::array<uint8_t, 32> out{};
|
|
114
|
+
for (int i = 0; i < 8; i++) {
|
|
115
|
+
out[i * 4] = (uint8_t)(h_[i] >> 24); out[i * 4 + 1] = (uint8_t)(h_[i] >> 16);
|
|
116
|
+
out[i * 4 + 2] = (uint8_t)(h_[i] >> 8); out[i * 4 + 3] = (uint8_t)h_[i];
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
std::string Sha256::hex_digest() {
|
|
122
|
+
auto d = digest();
|
|
123
|
+
return to_hex(d.data(), d.size());
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
std::string sha256_hex(const std::string &data) {
|
|
127
|
+
Sha256 h;
|
|
128
|
+
h.update(data);
|
|
129
|
+
return h.hex_digest();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
std::optional<std::string> sha256_file_hex(const std::string &path) {
|
|
133
|
+
FILE *f = std::fopen(path.c_str(), "rb");
|
|
134
|
+
if (!f) return std::nullopt;
|
|
135
|
+
Sha256 h;
|
|
136
|
+
std::vector<uint8_t> buf(1 << 16);
|
|
137
|
+
size_t n;
|
|
138
|
+
while ((n = std::fread(buf.data(), 1, buf.size(), f)) > 0) h.update(buf.data(), n);
|
|
139
|
+
bool failed = std::ferror(f) != 0;
|
|
140
|
+
std::fclose(f);
|
|
141
|
+
if (failed) return std::nullopt;
|
|
142
|
+
return h.hex_digest();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
std::string to_hex(const uint8_t *data, size_t size) {
|
|
146
|
+
static const char digits[] = "0123456789abcdef";
|
|
147
|
+
std::string out(size * 2, '0');
|
|
148
|
+
for (size_t i = 0; i < size; i++) {
|
|
149
|
+
out[i * 2] = digits[data[i] >> 4];
|
|
150
|
+
out[i * 2 + 1] = digits[data[i] & 15];
|
|
151
|
+
}
|
|
152
|
+
return out;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
std::string base64_encode(const uint8_t *data, size_t size) {
|
|
156
|
+
static const char tbl[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
157
|
+
std::string out;
|
|
158
|
+
out.reserve((size + 2) / 3 * 4);
|
|
159
|
+
for (size_t i = 0; i < size; i += 3) {
|
|
160
|
+
uint32_t v = (uint32_t)data[i] << 16;
|
|
161
|
+
if (i + 1 < size) v |= (uint32_t)data[i + 1] << 8;
|
|
162
|
+
if (i + 2 < size) v |= data[i + 2];
|
|
163
|
+
out += tbl[(v >> 18) & 63];
|
|
164
|
+
out += tbl[(v >> 12) & 63];
|
|
165
|
+
out += i + 1 < size ? tbl[(v >> 6) & 63] : '=';
|
|
166
|
+
out += i + 2 < size ? tbl[v & 63] : '=';
|
|
167
|
+
}
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
std::optional<std::vector<uint8_t>> base64_decode(const std::string &text) {
|
|
172
|
+
std::vector<uint8_t> out;
|
|
173
|
+
uint32_t acc = 0;
|
|
174
|
+
int bits = 0;
|
|
175
|
+
size_t symbols = 0;
|
|
176
|
+
bool padding = false;
|
|
177
|
+
for (char c : text) {
|
|
178
|
+
int v;
|
|
179
|
+
if (c >= 'A' && c <= 'Z') v = c - 'A';
|
|
180
|
+
else if (c >= 'a' && c <= 'z') v = c - 'a' + 26;
|
|
181
|
+
else if (c >= '0' && c <= '9') v = c - '0' + 52;
|
|
182
|
+
else if (c == '+' || c == '-') v = 62;
|
|
183
|
+
else if (c == '/' || c == '_') v = 63;
|
|
184
|
+
else if (c == '=') { padding = true; continue; }
|
|
185
|
+
else if (c == ' ' || c == '\n' || c == '\r' || c == '\t') continue;
|
|
186
|
+
else return std::nullopt;
|
|
187
|
+
if (padding) return std::nullopt; // data after '='
|
|
188
|
+
acc = (acc << 6) | (uint32_t)v;
|
|
189
|
+
bits += 6;
|
|
190
|
+
symbols++;
|
|
191
|
+
if (bits >= 8) {
|
|
192
|
+
bits -= 8;
|
|
193
|
+
out.push_back((uint8_t)(acc >> bits));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
if (symbols % 4 == 1) return std::nullopt;
|
|
197
|
+
return out;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
std::optional<PublicKey> parse_public_key(const std::string &value) {
|
|
201
|
+
std::string text = trim(value);
|
|
202
|
+
if (text.empty()) return std::nullopt;
|
|
203
|
+
if (text.find("-----BEGIN") != std::string::npos) return key_from_pem(text);
|
|
204
|
+
auto decoded = base64_decode(text);
|
|
205
|
+
if (!decoded) return std::nullopt;
|
|
206
|
+
std::string as_text(decoded->begin(), decoded->end());
|
|
207
|
+
if (as_text.find("-----BEGIN") != std::string::npos) return key_from_pem(as_text);
|
|
208
|
+
return key_from_der(*decoded);
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
bool ed25519_verify(const PublicKey &key, const std::string &message, const std::string &signature_b64) {
|
|
212
|
+
auto sig = base64_decode(signature_b64);
|
|
213
|
+
if (!sig || sig->size() != 64) return false;
|
|
214
|
+
return crypto_ed25519_check(sig->data(), key.data(), reinterpret_cast<const uint8_t *>(message.data()),
|
|
215
|
+
message.size()) == 0;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
bool equal_ct(const std::string &a, const std::string &b) {
|
|
219
|
+
if (a.size() != b.size()) return false;
|
|
220
|
+
unsigned char diff = 0;
|
|
221
|
+
for (size_t i = 0; i < a.size(); i++) diff |= (unsigned char)(a[i] ^ b[i]);
|
|
222
|
+
return diff == 0;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
} // namespace apn
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
// SHA-256, hex, base64 and Ed25519 verification (Monocypher) for ap_native.
|
|
2
|
+
#pragma once
|
|
3
|
+
|
|
4
|
+
#include <array>
|
|
5
|
+
#include <cstddef>
|
|
6
|
+
#include <cstdint>
|
|
7
|
+
#include <optional>
|
|
8
|
+
#include <string>
|
|
9
|
+
#include <vector>
|
|
10
|
+
|
|
11
|
+
namespace apn {
|
|
12
|
+
|
|
13
|
+
class Sha256 {
|
|
14
|
+
public:
|
|
15
|
+
Sha256();
|
|
16
|
+
void update(const void *data, size_t size);
|
|
17
|
+
void update(const std::string &s) { update(s.data(), s.size()); }
|
|
18
|
+
std::array<uint8_t, 32> digest(); // finalizes; the object must not be reused
|
|
19
|
+
std::string hex_digest();
|
|
20
|
+
|
|
21
|
+
private:
|
|
22
|
+
void block(const uint8_t *p);
|
|
23
|
+
uint32_t h_[8];
|
|
24
|
+
uint8_t buf_[64];
|
|
25
|
+
size_t buf_len_ = 0;
|
|
26
|
+
uint64_t total_ = 0;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
std::string sha256_hex(const std::string &data);
|
|
30
|
+
// Streams a file. nullopt when it cannot be read.
|
|
31
|
+
std::optional<std::string> sha256_file_hex(const std::string &path);
|
|
32
|
+
|
|
33
|
+
std::string to_hex(const uint8_t *data, size_t size);
|
|
34
|
+
std::string base64_encode(const uint8_t *data, size_t size);
|
|
35
|
+
// Standard or URL-safe alphabet, optional padding, whitespace ignored.
|
|
36
|
+
// nullopt on any other character or impossible length.
|
|
37
|
+
std::optional<std::vector<uint8_t>> base64_decode(const std::string &text);
|
|
38
|
+
|
|
39
|
+
using PublicKey = std::array<uint8_t, 32>;
|
|
40
|
+
|
|
41
|
+
// Accepts the same forms as the JS runtime's publicKeyPem(): PEM text, base64
|
|
42
|
+
// of a PEM, base64 of the SPKI DER; plus base64 of the raw 32-byte key.
|
|
43
|
+
std::optional<PublicKey> parse_public_key(const std::string &value);
|
|
44
|
+
|
|
45
|
+
// Ed25519 (RFC 8032, pure) verification of a base64 signature over message.
|
|
46
|
+
bool ed25519_verify(const PublicKey &key, const std::string &message, const std::string &signature_b64);
|
|
47
|
+
|
|
48
|
+
// Constant-time-ish comparison for hex digests.
|
|
49
|
+
bool equal_ct(const std::string &a, const std::string &b);
|
|
50
|
+
|
|
51
|
+
} // namespace apn
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
#include "dialog.hpp"
|
|
2
|
+
|
|
3
|
+
namespace apn {
|
|
4
|
+
|
|
5
|
+
DialogModel options_dialog_model(const std::string &title, const LicenseView &license, const UpdateView &update,
|
|
6
|
+
const std::string ¬ice, const std::string &product_url,
|
|
7
|
+
const std::string &manage_devices_url) {
|
|
8
|
+
DialogModel m;
|
|
9
|
+
m.title = title.empty() ? "License" : title;
|
|
10
|
+
m.message = license.message;
|
|
11
|
+
if (!license.username.empty() && is_runnable(license.status) && license.status != Status::Disabled) {
|
|
12
|
+
m.details = "Signed in as " + license.username + ".";
|
|
13
|
+
}
|
|
14
|
+
if (!notice.empty()) {
|
|
15
|
+
if (!m.details.empty()) m.details += "\n\n";
|
|
16
|
+
m.details += notice + ".";
|
|
17
|
+
}
|
|
18
|
+
if (!update.change_log.empty() &&
|
|
19
|
+
(update.status == UpdStatus::Applied || update.status == UpdStatus::Staged || update.status == UpdStatus::Available)) {
|
|
20
|
+
std::string log = update.change_log.size() > 1200 ? update.change_log.substr(0, 1200) + "\xE2\x80\xA6" : update.change_log;
|
|
21
|
+
m.details += "\n\nWhat's new in v" + update.version + ":\n" + log;
|
|
22
|
+
}
|
|
23
|
+
auto add = [&](const std::string &label, DialogAction a) { m.buttons.push_back({label, a}); };
|
|
24
|
+
switch (license.status) {
|
|
25
|
+
case Status::Disabled:
|
|
26
|
+
add("OK", DialogAction::Close);
|
|
27
|
+
break;
|
|
28
|
+
case Status::SignedOut:
|
|
29
|
+
add("Sign in\xE2\x80\xA6", DialogAction::SignIn);
|
|
30
|
+
if (!product_url.empty()) add("Buy\xE2\x80\xA6", DialogAction::OpenProduct);
|
|
31
|
+
add("Close", DialogAction::Close);
|
|
32
|
+
break;
|
|
33
|
+
case Status::SigningIn:
|
|
34
|
+
add("Open sign-in page", DialogAction::OpenSignInPage);
|
|
35
|
+
add("Cancel sign-in", DialogAction::CancelSignIn);
|
|
36
|
+
add("Close", DialogAction::Close);
|
|
37
|
+
break;
|
|
38
|
+
case Status::NotOwned:
|
|
39
|
+
case Status::Refunded:
|
|
40
|
+
if (!product_url.empty()) add("Buy\xE2\x80\xA6", DialogAction::OpenProduct);
|
|
41
|
+
add("Use another account", DialogAction::SignOut);
|
|
42
|
+
add("Close", DialogAction::Close);
|
|
43
|
+
break;
|
|
44
|
+
case Status::Active:
|
|
45
|
+
case Status::OfflineGrace:
|
|
46
|
+
add("OK", DialogAction::Close);
|
|
47
|
+
add("Sign out", DialogAction::SignOut);
|
|
48
|
+
if (!manage_devices_url.empty()) add("Manage devices\xE2\x80\xA6", DialogAction::ManageDevices);
|
|
49
|
+
break;
|
|
50
|
+
case Status::Checking:
|
|
51
|
+
case Status::OfflineExpired:
|
|
52
|
+
case Status::Error:
|
|
53
|
+
add("Try again", DialogAction::Retry);
|
|
54
|
+
add("Sign out", DialogAction::SignOut);
|
|
55
|
+
add("Close", DialogAction::Close);
|
|
56
|
+
break;
|
|
57
|
+
}
|
|
58
|
+
if (m.buttons.size() > 3) m.buttons.resize(3);
|
|
59
|
+
return m;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
} // namespace apn
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
// The Options dialog (PF_Cmd_DO_DIALOG): what it shows and which buttons it
|
|
2
|
+
// offers for each license/update state. Pure, so it is unit tested; the
|
|
3
|
+
// platform files only present it (NSAlert / TaskDialog).
|
|
4
|
+
#pragma once
|
|
5
|
+
|
|
6
|
+
#include <string>
|
|
7
|
+
#include <vector>
|
|
8
|
+
|
|
9
|
+
#include "engine.hpp"
|
|
10
|
+
|
|
11
|
+
namespace apn {
|
|
12
|
+
|
|
13
|
+
enum class DialogAction { Close, SignIn, OpenSignInPage, CancelSignIn, SignOut, Retry, OpenProduct, ManageDevices };
|
|
14
|
+
|
|
15
|
+
struct DialogButton {
|
|
16
|
+
std::string label;
|
|
17
|
+
DialogAction action;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
struct DialogModel {
|
|
21
|
+
std::string title; // the effect's name
|
|
22
|
+
std::string message; // first line: the license state
|
|
23
|
+
std::string details; // account, update notice, changelog
|
|
24
|
+
std::vector<DialogButton> buttons; // first = default; at most 3
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
DialogModel options_dialog_model(const std::string &title, const LicenseView &license, const UpdateView &update,
|
|
28
|
+
const std::string ¬ice, const std::string &product_url,
|
|
29
|
+
const std::string &manage_devices_url);
|
|
30
|
+
|
|
31
|
+
// Shows the dialog modally on the calling (UI) thread; returns the index of the
|
|
32
|
+
// pressed button, or -1 when it could not be shown.
|
|
33
|
+
int platform_show_dialog(const DialogModel &model);
|
|
34
|
+
|
|
35
|
+
} // namespace apn
|