konpeito 0.1.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.
- checksums.yaml +7 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +75 -0
- data/CONTRIBUTING.md +123 -0
- data/LICENSE +21 -0
- data/README.md +257 -0
- data/Rakefile +11 -0
- data/bin/konpeito +6 -0
- data/konpeito.gemspec +43 -0
- data/lib/konpeito/ast/typed_ast.rb +620 -0
- data/lib/konpeito/ast/visitor.rb +78 -0
- data/lib/konpeito/cache/cache_manager.rb +230 -0
- data/lib/konpeito/cache/dependency_graph.rb +192 -0
- data/lib/konpeito/cache.rb +8 -0
- data/lib/konpeito/cli/base_command.rb +187 -0
- data/lib/konpeito/cli/build_command.rb +220 -0
- data/lib/konpeito/cli/check_command.rb +104 -0
- data/lib/konpeito/cli/config.rb +231 -0
- data/lib/konpeito/cli/deps_command.rb +128 -0
- data/lib/konpeito/cli/doctor_command.rb +340 -0
- data/lib/konpeito/cli/fmt_command.rb +199 -0
- data/lib/konpeito/cli/init_command.rb +312 -0
- data/lib/konpeito/cli/lsp_command.rb +40 -0
- data/lib/konpeito/cli/run_command.rb +150 -0
- data/lib/konpeito/cli/test_command.rb +248 -0
- data/lib/konpeito/cli/watch_command.rb +212 -0
- data/lib/konpeito/cli.rb +301 -0
- data/lib/konpeito/codegen/builtin_methods.rb +229 -0
- data/lib/konpeito/codegen/cruby_backend.rb +1090 -0
- data/lib/konpeito/codegen/debug_info.rb +352 -0
- data/lib/konpeito/codegen/inliner.rb +486 -0
- data/lib/konpeito/codegen/jvm_backend.rb +197 -0
- data/lib/konpeito/codegen/jvm_generator.rb +13412 -0
- data/lib/konpeito/codegen/llvm_generator.rb +13191 -0
- data/lib/konpeito/codegen/loop_optimizer.rb +363 -0
- data/lib/konpeito/codegen/monomorphizer.rb +359 -0
- data/lib/konpeito/codegen/profile_runtime.c +341 -0
- data/lib/konpeito/codegen/profiler.rb +99 -0
- data/lib/konpeito/compiler.rb +592 -0
- data/lib/konpeito/dependency_resolver.rb +296 -0
- data/lib/konpeito/diagnostics/collector.rb +127 -0
- data/lib/konpeito/diagnostics/diagnostic.rb +237 -0
- data/lib/konpeito/diagnostics/renderer.rb +144 -0
- data/lib/konpeito/formatter/formatter.rb +1214 -0
- data/lib/konpeito/hir/builder.rb +7167 -0
- data/lib/konpeito/hir/nodes.rb +2465 -0
- data/lib/konpeito/lsp/document_manager.rb +820 -0
- data/lib/konpeito/lsp/server.rb +183 -0
- data/lib/konpeito/lsp/transport.rb +38 -0
- data/lib/konpeito/parser/prism_adapter.rb +65 -0
- data/lib/konpeito/platform.rb +103 -0
- data/lib/konpeito/profile/report.rb +136 -0
- data/lib/konpeito/rbs_inline/preprocessor.rb +199 -0
- data/lib/konpeito/stdlib/compression/compression.rb +72 -0
- data/lib/konpeito/stdlib/compression/compression.rbs +60 -0
- data/lib/konpeito/stdlib/compression/compression_native.c +415 -0
- data/lib/konpeito/stdlib/compression/extconf.rb +19 -0
- data/lib/konpeito/stdlib/crypto/crypto.rb +85 -0
- data/lib/konpeito/stdlib/crypto/crypto.rbs +74 -0
- data/lib/konpeito/stdlib/crypto/crypto_native.c +312 -0
- data/lib/konpeito/stdlib/crypto/extconf.rb +40 -0
- data/lib/konpeito/stdlib/http/extconf.rb +19 -0
- data/lib/konpeito/stdlib/http/http.rb +125 -0
- data/lib/konpeito/stdlib/http/http.rbs +57 -0
- data/lib/konpeito/stdlib/http/http_native.c +440 -0
- data/lib/konpeito/stdlib/json/extconf.rb +17 -0
- data/lib/konpeito/stdlib/json/json.rb +44 -0
- data/lib/konpeito/stdlib/json/json.rbs +33 -0
- data/lib/konpeito/stdlib/json/json_native.c +286 -0
- data/lib/konpeito/stdlib/ui/extconf.rb +216 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.cpp +1625 -0
- data/lib/konpeito/stdlib/ui/konpeito_ui_native.h +162 -0
- data/lib/konpeito/stdlib/ui/ui.rb +318 -0
- data/lib/konpeito/stdlib/ui/ui.rbs +247 -0
- data/lib/konpeito/type_checker/annotation_parser.rb +67 -0
- data/lib/konpeito/type_checker/hm_inferrer.rb +2565 -0
- data/lib/konpeito/type_checker/inferrer.rb +565 -0
- data/lib/konpeito/type_checker/rbs_loader.rb +1621 -0
- data/lib/konpeito/type_checker/type_resolver.rb +276 -0
- data/lib/konpeito/type_checker/types.rb +1434 -0
- data/lib/konpeito/type_checker/unification.rb +323 -0
- data/lib/konpeito/ui/animation/animated_state.rb +80 -0
- data/lib/konpeito/ui/animation/easing.rb +59 -0
- data/lib/konpeito/ui/animation/value_tween.rb +66 -0
- data/lib/konpeito/ui/app.rb +379 -0
- data/lib/konpeito/ui/box.rb +38 -0
- data/lib/konpeito/ui/castella.rb +70 -0
- data/lib/konpeito/ui/castella_native.rb +76 -0
- data/lib/konpeito/ui/chart/area_chart.rb +305 -0
- data/lib/konpeito/ui/chart/bar_chart.rb +288 -0
- data/lib/konpeito/ui/chart/base_chart.rb +210 -0
- data/lib/konpeito/ui/chart/chart_helpers.rb +79 -0
- data/lib/konpeito/ui/chart/gauge_chart.rb +171 -0
- data/lib/konpeito/ui/chart/heatmap_chart.rb +222 -0
- data/lib/konpeito/ui/chart/line_chart.rb +289 -0
- data/lib/konpeito/ui/chart/pie_chart.rb +219 -0
- data/lib/konpeito/ui/chart/scales.rb +77 -0
- data/lib/konpeito/ui/chart/scatter_chart.rb +303 -0
- data/lib/konpeito/ui/chart/stacked_bar_chart.rb +276 -0
- data/lib/konpeito/ui/column.rb +271 -0
- data/lib/konpeito/ui/core.rb +2199 -0
- data/lib/konpeito/ui/dsl.rb +443 -0
- data/lib/konpeito/ui/frame.rb +171 -0
- data/lib/konpeito/ui/frame_native.rb +494 -0
- data/lib/konpeito/ui/markdown/ast.rb +124 -0
- data/lib/konpeito/ui/markdown/mermaid/layout.rb +387 -0
- data/lib/konpeito/ui/markdown/mermaid/models.rb +232 -0
- data/lib/konpeito/ui/markdown/mermaid/parser.rb +519 -0
- data/lib/konpeito/ui/markdown/mermaid/renderer.rb +336 -0
- data/lib/konpeito/ui/markdown/parser.rb +805 -0
- data/lib/konpeito/ui/markdown/renderer.rb +639 -0
- data/lib/konpeito/ui/markdown/theme.rb +165 -0
- data/lib/konpeito/ui/render_node.rb +260 -0
- data/lib/konpeito/ui/row.rb +207 -0
- data/lib/konpeito/ui/spacer.rb +18 -0
- data/lib/konpeito/ui/style.rb +799 -0
- data/lib/konpeito/ui/theme.rb +563 -0
- data/lib/konpeito/ui/themes/material.rb +35 -0
- data/lib/konpeito/ui/themes/tokyo_night.rb +6 -0
- data/lib/konpeito/ui/widgets/button.rb +103 -0
- data/lib/konpeito/ui/widgets/calendar.rb +1034 -0
- data/lib/konpeito/ui/widgets/checkbox.rb +119 -0
- data/lib/konpeito/ui/widgets/container.rb +91 -0
- data/lib/konpeito/ui/widgets/data_table.rb +667 -0
- data/lib/konpeito/ui/widgets/divider.rb +29 -0
- data/lib/konpeito/ui/widgets/image.rb +105 -0
- data/lib/konpeito/ui/widgets/input.rb +485 -0
- data/lib/konpeito/ui/widgets/markdown.rb +57 -0
- data/lib/konpeito/ui/widgets/modal.rb +163 -0
- data/lib/konpeito/ui/widgets/multiline_input.rb +968 -0
- data/lib/konpeito/ui/widgets/multiline_text.rb +180 -0
- data/lib/konpeito/ui/widgets/net_image.rb +100 -0
- data/lib/konpeito/ui/widgets/progress_bar.rb +70 -0
- data/lib/konpeito/ui/widgets/radio_buttons.rb +93 -0
- data/lib/konpeito/ui/widgets/slider.rb +133 -0
- data/lib/konpeito/ui/widgets/switch.rb +84 -0
- data/lib/konpeito/ui/widgets/tabs.rb +157 -0
- data/lib/konpeito/ui/widgets/text.rb +110 -0
- data/lib/konpeito/ui/widgets/tree.rb +426 -0
- data/lib/konpeito/version.rb +5 -0
- data/lib/konpeito.rb +109 -0
- data/test_native_array.rb +172 -0
- data/test_native_array_class.rb +197 -0
- data/test_native_class.rb +151 -0
- data/tools/konpeito-asm/build.sh +65 -0
- data/tools/konpeito-asm/lib/asm-9.7.1.jar +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KArray.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCompression.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KConditionVariable.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KCrypto.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KFile.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHTTP.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KHash.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON$Parser.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KJSON.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KMath.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactor.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KRactorPort.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KSizedQueue.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KThread.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/KTime.class +0 -0
- data/tools/konpeito-asm/runtime-classes/konpeito/runtime/RubyDispatch.class +0 -0
- data/tools/konpeito-asm/src/ClassIntrospector.java +312 -0
- data/tools/konpeito-asm/src/KonpeitoAssembler.java +659 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KArray.java +390 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCompression.java +168 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KConditionVariable.java +48 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KCrypto.java +151 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KFile.java +100 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHTTP.java +113 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KHash.java +228 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KJSON.java +405 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KMath.java +54 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactor.java +244 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KRactorPort.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KSizedQueue.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KThread.java +49 -0
- data/tools/konpeito-asm/src/konpeito/runtime/KTime.java +53 -0
- data/tools/konpeito-asm/src/konpeito/runtime/RubyDispatch.java +416 -0
- metadata +267 -0
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Konpeito Crypto stdlib - OpenSSL wrapper
|
|
3
|
+
*
|
|
4
|
+
* Provides cryptographic functionality using OpenSSL.
|
|
5
|
+
* Supports SHA256, SHA512, HMAC, and secure random bytes.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
#include <ruby.h>
|
|
9
|
+
#include <openssl/sha.h>
|
|
10
|
+
#include <openssl/hmac.h>
|
|
11
|
+
#include <openssl/rand.h>
|
|
12
|
+
#include <openssl/evp.h>
|
|
13
|
+
#include <string.h>
|
|
14
|
+
|
|
15
|
+
/*
|
|
16
|
+
* Convert binary data to hex string
|
|
17
|
+
*/
|
|
18
|
+
static VALUE binary_to_hex(const unsigned char *data, size_t len) {
|
|
19
|
+
char *hex = malloc(len * 2 + 1);
|
|
20
|
+
if (!hex) {
|
|
21
|
+
rb_raise(rb_eNoMemError, "Failed to allocate hex string");
|
|
22
|
+
return Qnil;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
for (size_t i = 0; i < len; i++) {
|
|
26
|
+
sprintf(hex + i * 2, "%02x", data[i]);
|
|
27
|
+
}
|
|
28
|
+
hex[len * 2] = '\0';
|
|
29
|
+
|
|
30
|
+
VALUE result = rb_utf8_str_new(hex, len * 2);
|
|
31
|
+
free(hex);
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
* Compute SHA256 hash
|
|
37
|
+
*
|
|
38
|
+
* @param data [String] Data to hash
|
|
39
|
+
* @return [String] Hex-encoded SHA256 hash (64 characters)
|
|
40
|
+
*/
|
|
41
|
+
VALUE konpeito_crypto_sha256(VALUE self, VALUE data) {
|
|
42
|
+
Check_Type(data, T_STRING);
|
|
43
|
+
|
|
44
|
+
const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
|
|
45
|
+
size_t input_len = RSTRING_LEN(data);
|
|
46
|
+
|
|
47
|
+
unsigned char hash[SHA256_DIGEST_LENGTH];
|
|
48
|
+
SHA256(input, input_len, hash);
|
|
49
|
+
|
|
50
|
+
return binary_to_hex(hash, SHA256_DIGEST_LENGTH);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/*
|
|
54
|
+
* Compute SHA256 hash (binary output)
|
|
55
|
+
*
|
|
56
|
+
* @param data [String] Data to hash
|
|
57
|
+
* @return [String] Binary SHA256 hash (32 bytes)
|
|
58
|
+
*/
|
|
59
|
+
VALUE konpeito_crypto_sha256_binary(VALUE self, VALUE data) {
|
|
60
|
+
Check_Type(data, T_STRING);
|
|
61
|
+
|
|
62
|
+
const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
|
|
63
|
+
size_t input_len = RSTRING_LEN(data);
|
|
64
|
+
|
|
65
|
+
unsigned char hash[SHA256_DIGEST_LENGTH];
|
|
66
|
+
SHA256(input, input_len, hash);
|
|
67
|
+
|
|
68
|
+
return rb_str_new((const char *)hash, SHA256_DIGEST_LENGTH);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/*
|
|
72
|
+
* Compute SHA512 hash
|
|
73
|
+
*
|
|
74
|
+
* @param data [String] Data to hash
|
|
75
|
+
* @return [String] Hex-encoded SHA512 hash (128 characters)
|
|
76
|
+
*/
|
|
77
|
+
VALUE konpeito_crypto_sha512(VALUE self, VALUE data) {
|
|
78
|
+
Check_Type(data, T_STRING);
|
|
79
|
+
|
|
80
|
+
const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
|
|
81
|
+
size_t input_len = RSTRING_LEN(data);
|
|
82
|
+
|
|
83
|
+
unsigned char hash[SHA512_DIGEST_LENGTH];
|
|
84
|
+
SHA512(input, input_len, hash);
|
|
85
|
+
|
|
86
|
+
return binary_to_hex(hash, SHA512_DIGEST_LENGTH);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/*
|
|
90
|
+
* Compute SHA512 hash (binary output)
|
|
91
|
+
*
|
|
92
|
+
* @param data [String] Data to hash
|
|
93
|
+
* @return [String] Binary SHA512 hash (64 bytes)
|
|
94
|
+
*/
|
|
95
|
+
VALUE konpeito_crypto_sha512_binary(VALUE self, VALUE data) {
|
|
96
|
+
Check_Type(data, T_STRING);
|
|
97
|
+
|
|
98
|
+
const unsigned char *input = (const unsigned char *)RSTRING_PTR(data);
|
|
99
|
+
size_t input_len = RSTRING_LEN(data);
|
|
100
|
+
|
|
101
|
+
unsigned char hash[SHA512_DIGEST_LENGTH];
|
|
102
|
+
SHA512(input, input_len, hash);
|
|
103
|
+
|
|
104
|
+
return rb_str_new((const char *)hash, SHA512_DIGEST_LENGTH);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/*
|
|
108
|
+
* Compute HMAC-SHA256
|
|
109
|
+
*
|
|
110
|
+
* @param key [String] Secret key
|
|
111
|
+
* @param data [String] Data to authenticate
|
|
112
|
+
* @return [String] Hex-encoded HMAC-SHA256 (64 characters)
|
|
113
|
+
*/
|
|
114
|
+
VALUE konpeito_crypto_hmac_sha256(VALUE self, VALUE key, VALUE data) {
|
|
115
|
+
Check_Type(key, T_STRING);
|
|
116
|
+
Check_Type(data, T_STRING);
|
|
117
|
+
|
|
118
|
+
const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
|
|
119
|
+
size_t key_len = RSTRING_LEN(key);
|
|
120
|
+
const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
|
|
121
|
+
size_t data_len = RSTRING_LEN(data);
|
|
122
|
+
|
|
123
|
+
unsigned char result[EVP_MAX_MD_SIZE];
|
|
124
|
+
unsigned int result_len;
|
|
125
|
+
|
|
126
|
+
HMAC(EVP_sha256(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
|
|
127
|
+
|
|
128
|
+
return binary_to_hex(result, result_len);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/*
|
|
132
|
+
* Compute HMAC-SHA256 (binary output)
|
|
133
|
+
*
|
|
134
|
+
* @param key [String] Secret key
|
|
135
|
+
* @param data [String] Data to authenticate
|
|
136
|
+
* @return [String] Binary HMAC-SHA256 (32 bytes)
|
|
137
|
+
*/
|
|
138
|
+
VALUE konpeito_crypto_hmac_sha256_binary(VALUE self, VALUE key, VALUE data) {
|
|
139
|
+
Check_Type(key, T_STRING);
|
|
140
|
+
Check_Type(data, T_STRING);
|
|
141
|
+
|
|
142
|
+
const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
|
|
143
|
+
size_t key_len = RSTRING_LEN(key);
|
|
144
|
+
const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
|
|
145
|
+
size_t data_len = RSTRING_LEN(data);
|
|
146
|
+
|
|
147
|
+
unsigned char result[EVP_MAX_MD_SIZE];
|
|
148
|
+
unsigned int result_len;
|
|
149
|
+
|
|
150
|
+
HMAC(EVP_sha256(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
|
|
151
|
+
|
|
152
|
+
return rb_str_new((const char *)result, result_len);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/*
|
|
156
|
+
* Compute HMAC-SHA512
|
|
157
|
+
*
|
|
158
|
+
* @param key [String] Secret key
|
|
159
|
+
* @param data [String] Data to authenticate
|
|
160
|
+
* @return [String] Hex-encoded HMAC-SHA512 (128 characters)
|
|
161
|
+
*/
|
|
162
|
+
VALUE konpeito_crypto_hmac_sha512(VALUE self, VALUE key, VALUE data) {
|
|
163
|
+
Check_Type(key, T_STRING);
|
|
164
|
+
Check_Type(data, T_STRING);
|
|
165
|
+
|
|
166
|
+
const unsigned char *key_ptr = (const unsigned char *)RSTRING_PTR(key);
|
|
167
|
+
size_t key_len = RSTRING_LEN(key);
|
|
168
|
+
const unsigned char *data_ptr = (const unsigned char *)RSTRING_PTR(data);
|
|
169
|
+
size_t data_len = RSTRING_LEN(data);
|
|
170
|
+
|
|
171
|
+
unsigned char result[EVP_MAX_MD_SIZE];
|
|
172
|
+
unsigned int result_len;
|
|
173
|
+
|
|
174
|
+
HMAC(EVP_sha512(), key_ptr, (int)key_len, data_ptr, data_len, result, &result_len);
|
|
175
|
+
|
|
176
|
+
return binary_to_hex(result, result_len);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/*
|
|
180
|
+
* Generate cryptographically secure random bytes
|
|
181
|
+
*
|
|
182
|
+
* @param count [Integer] Number of bytes to generate
|
|
183
|
+
* @return [String] Binary string of random bytes
|
|
184
|
+
* @raise [RuntimeError] if random generation fails
|
|
185
|
+
*/
|
|
186
|
+
VALUE konpeito_crypto_random_bytes(VALUE self, VALUE count) {
|
|
187
|
+
int num_bytes = NUM2INT(count);
|
|
188
|
+
|
|
189
|
+
if (num_bytes <= 0) {
|
|
190
|
+
rb_raise(rb_eArgError, "count must be positive");
|
|
191
|
+
return Qnil;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (num_bytes > 1024 * 1024) { /* 1MB limit */
|
|
195
|
+
rb_raise(rb_eArgError, "count too large (max 1MB)");
|
|
196
|
+
return Qnil;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
unsigned char *buf = malloc(num_bytes);
|
|
200
|
+
if (!buf) {
|
|
201
|
+
rb_raise(rb_eNoMemError, "Failed to allocate random buffer");
|
|
202
|
+
return Qnil;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (RAND_bytes(buf, num_bytes) != 1) {
|
|
206
|
+
free(buf);
|
|
207
|
+
rb_raise(rb_eRuntimeError, "Failed to generate random bytes");
|
|
208
|
+
return Qnil;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
VALUE result = rb_str_new((const char *)buf, num_bytes);
|
|
212
|
+
free(buf);
|
|
213
|
+
|
|
214
|
+
return result;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/*
|
|
218
|
+
* Generate cryptographically secure random bytes as hex string
|
|
219
|
+
*
|
|
220
|
+
* @param count [Integer] Number of bytes to generate (output will be 2x this length)
|
|
221
|
+
* @return [String] Hex-encoded random bytes
|
|
222
|
+
* @raise [RuntimeError] if random generation fails
|
|
223
|
+
*/
|
|
224
|
+
VALUE konpeito_crypto_random_hex(VALUE self, VALUE count) {
|
|
225
|
+
int num_bytes = NUM2INT(count);
|
|
226
|
+
|
|
227
|
+
if (num_bytes <= 0) {
|
|
228
|
+
rb_raise(rb_eArgError, "count must be positive");
|
|
229
|
+
return Qnil;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
if (num_bytes > 1024 * 1024) { /* 1MB limit */
|
|
233
|
+
rb_raise(rb_eArgError, "count too large (max 1MB)");
|
|
234
|
+
return Qnil;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
unsigned char *buf = malloc(num_bytes);
|
|
238
|
+
if (!buf) {
|
|
239
|
+
rb_raise(rb_eNoMemError, "Failed to allocate random buffer");
|
|
240
|
+
return Qnil;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
if (RAND_bytes(buf, num_bytes) != 1) {
|
|
244
|
+
free(buf);
|
|
245
|
+
rb_raise(rb_eRuntimeError, "Failed to generate random bytes");
|
|
246
|
+
return Qnil;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
VALUE result = binary_to_hex(buf, num_bytes);
|
|
250
|
+
free(buf);
|
|
251
|
+
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/*
|
|
256
|
+
* Constant-time comparison of two strings
|
|
257
|
+
* Prevents timing attacks when comparing secrets
|
|
258
|
+
*
|
|
259
|
+
* @param a [String] First string
|
|
260
|
+
* @param b [String] Second string
|
|
261
|
+
* @return [Boolean] true if strings are equal, false otherwise
|
|
262
|
+
*/
|
|
263
|
+
VALUE konpeito_crypto_secure_compare(VALUE self, VALUE a, VALUE b) {
|
|
264
|
+
Check_Type(a, T_STRING);
|
|
265
|
+
Check_Type(b, T_STRING);
|
|
266
|
+
|
|
267
|
+
size_t a_len = RSTRING_LEN(a);
|
|
268
|
+
size_t b_len = RSTRING_LEN(b);
|
|
269
|
+
|
|
270
|
+
/* Length must match */
|
|
271
|
+
if (a_len != b_len) {
|
|
272
|
+
return Qfalse;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const unsigned char *a_ptr = (const unsigned char *)RSTRING_PTR(a);
|
|
276
|
+
const unsigned char *b_ptr = (const unsigned char *)RSTRING_PTR(b);
|
|
277
|
+
|
|
278
|
+
/* Constant-time comparison */
|
|
279
|
+
unsigned char result = 0;
|
|
280
|
+
for (size_t i = 0; i < a_len; i++) {
|
|
281
|
+
result |= a_ptr[i] ^ b_ptr[i];
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
return result == 0 ? Qtrue : Qfalse;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Module initialization */
|
|
288
|
+
void Init_konpeito_crypto(void) {
|
|
289
|
+
VALUE mKonpeitoCrypto = rb_define_module("KonpeitoCrypto");
|
|
290
|
+
|
|
291
|
+
/* Hash functions (hex output) */
|
|
292
|
+
rb_define_module_function(mKonpeitoCrypto, "sha256", konpeito_crypto_sha256, 1);
|
|
293
|
+
rb_define_module_function(mKonpeitoCrypto, "sha512", konpeito_crypto_sha512, 1);
|
|
294
|
+
|
|
295
|
+
/* Hash functions (binary output) */
|
|
296
|
+
rb_define_module_function(mKonpeitoCrypto, "sha256_binary", konpeito_crypto_sha256_binary, 1);
|
|
297
|
+
rb_define_module_function(mKonpeitoCrypto, "sha512_binary", konpeito_crypto_sha512_binary, 1);
|
|
298
|
+
|
|
299
|
+
/* HMAC functions (hex output) */
|
|
300
|
+
rb_define_module_function(mKonpeitoCrypto, "hmac_sha256", konpeito_crypto_hmac_sha256, 2);
|
|
301
|
+
rb_define_module_function(mKonpeitoCrypto, "hmac_sha512", konpeito_crypto_hmac_sha512, 2);
|
|
302
|
+
|
|
303
|
+
/* HMAC functions (binary output) */
|
|
304
|
+
rb_define_module_function(mKonpeitoCrypto, "hmac_sha256_binary", konpeito_crypto_hmac_sha256_binary, 2);
|
|
305
|
+
|
|
306
|
+
/* Random generation */
|
|
307
|
+
rb_define_module_function(mKonpeitoCrypto, "random_bytes", konpeito_crypto_random_bytes, 1);
|
|
308
|
+
rb_define_module_function(mKonpeitoCrypto, "random_hex", konpeito_crypto_random_hex, 1);
|
|
309
|
+
|
|
310
|
+
/* Utilities */
|
|
311
|
+
rb_define_module_function(mKonpeitoCrypto, "secure_compare", konpeito_crypto_secure_compare, 2);
|
|
312
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# extconf.rb for konpeito_crypto
|
|
2
|
+
require 'mkmf'
|
|
3
|
+
|
|
4
|
+
# Check for OpenSSL
|
|
5
|
+
# macOS: Uses LibreSSL or OpenSSL from Homebrew
|
|
6
|
+
# Linux: Uses system OpenSSL
|
|
7
|
+
|
|
8
|
+
# Try to find OpenSSL (Homebrew on macOS)
|
|
9
|
+
openssl_dir = nil
|
|
10
|
+
['/opt/homebrew/opt/openssl@3', '/opt/homebrew/opt/openssl', '/usr/local/opt/openssl'].each do |dir|
|
|
11
|
+
if File.directory?(dir)
|
|
12
|
+
openssl_dir = dir
|
|
13
|
+
break
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
if openssl_dir
|
|
18
|
+
$INCFLAGS << " -I#{openssl_dir}/include"
|
|
19
|
+
$LDFLAGS << " -L#{openssl_dir}/lib"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Check for required libraries and headers
|
|
23
|
+
unless have_library('crypto') && have_header('openssl/sha.h')
|
|
24
|
+
abort <<~MSG
|
|
25
|
+
OpenSSL (libcrypto) is required for KonpeitoCrypto.
|
|
26
|
+
|
|
27
|
+
Installation:
|
|
28
|
+
macOS: brew install openssl
|
|
29
|
+
Ubuntu: sudo apt-get install libssl-dev
|
|
30
|
+
Fedora: sudo dnf install openssl-devel
|
|
31
|
+
|
|
32
|
+
If OpenSSL is installed but not found, try:
|
|
33
|
+
macOS: export PKG_CONFIG_PATH="/opt/homebrew/opt/openssl@3/lib/pkgconfig"
|
|
34
|
+
MSG
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Optimization flags
|
|
38
|
+
$CFLAGS << ' -O3'
|
|
39
|
+
|
|
40
|
+
create_makefile('konpeito_crypto')
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# extconf.rb for konpeito_http
|
|
2
|
+
require 'mkmf'
|
|
3
|
+
|
|
4
|
+
# Check for libcurl
|
|
5
|
+
unless have_library('curl') && have_header('curl/curl.h')
|
|
6
|
+
abort <<~MSG
|
|
7
|
+
libcurl is required for KonpeitoHTTP.
|
|
8
|
+
|
|
9
|
+
Installation:
|
|
10
|
+
macOS: brew install curl
|
|
11
|
+
Ubuntu: sudo apt-get install libcurl4-openssl-dev
|
|
12
|
+
Fedora: sudo dnf install libcurl-devel
|
|
13
|
+
MSG
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Optimization flags
|
|
17
|
+
$CFLAGS << ' -O3'
|
|
18
|
+
|
|
19
|
+
create_makefile('konpeito_http')
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# KonpeitoHTTP - Fast HTTP client using libcurl
|
|
2
|
+
#
|
|
3
|
+
# This module provides HTTP client functionality using the libcurl C library.
|
|
4
|
+
# It is implemented as a C extension for maximum performance.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# require 'konpeito/stdlib/http'
|
|
8
|
+
#
|
|
9
|
+
# # Simple GET request
|
|
10
|
+
# body = KonpeitoHTTP.get("https://example.com")
|
|
11
|
+
#
|
|
12
|
+
# # Simple POST request
|
|
13
|
+
# body = KonpeitoHTTP.post("https://api.example.com/data", '{"key": "value"}')
|
|
14
|
+
#
|
|
15
|
+
# # GET with full response details
|
|
16
|
+
# response = KonpeitoHTTP.get_response("https://example.com")
|
|
17
|
+
# puts response[:status] # => 200
|
|
18
|
+
# puts response[:body] # => "<!doctype html>..."
|
|
19
|
+
# puts response[:headers] # => {"Content-Type" => "text/html", ...}
|
|
20
|
+
#
|
|
21
|
+
# # POST with Content-Type
|
|
22
|
+
# response = KonpeitoHTTP.post_response(
|
|
23
|
+
# "https://api.example.com/json",
|
|
24
|
+
# '{"name": "Alice"}',
|
|
25
|
+
# "application/json"
|
|
26
|
+
# )
|
|
27
|
+
#
|
|
28
|
+
# # Generic request with custom method and headers
|
|
29
|
+
# response = KonpeitoHTTP.request(
|
|
30
|
+
# "PUT",
|
|
31
|
+
# "https://api.example.com/resource/123",
|
|
32
|
+
# '{"updated": true}',
|
|
33
|
+
# {"Authorization" => "Bearer token", "Content-Type" => "application/json"}
|
|
34
|
+
# )
|
|
35
|
+
|
|
36
|
+
# Try to load the native extension
|
|
37
|
+
begin
|
|
38
|
+
require_relative 'konpeito_http'
|
|
39
|
+
rescue LoadError => e
|
|
40
|
+
# Fallback to net/http if native extension is not available
|
|
41
|
+
require 'net/http'
|
|
42
|
+
require 'uri'
|
|
43
|
+
|
|
44
|
+
module KonpeitoHTTP
|
|
45
|
+
class << self
|
|
46
|
+
def get(url)
|
|
47
|
+
uri = URI.parse(url)
|
|
48
|
+
Net::HTTP.get(uri)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def post(url, body)
|
|
52
|
+
uri = URI.parse(url)
|
|
53
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
54
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
55
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
|
56
|
+
request.body = body
|
|
57
|
+
response = http.request(request)
|
|
58
|
+
response.body
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def get_response(url)
|
|
62
|
+
uri = URI.parse(url)
|
|
63
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
64
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
65
|
+
response = http.get(uri.request_uri)
|
|
66
|
+
headers = {}
|
|
67
|
+
response.each_header { |k, v| headers[k] = v }
|
|
68
|
+
{
|
|
69
|
+
status: response.code.to_i,
|
|
70
|
+
body: response.body,
|
|
71
|
+
headers: headers
|
|
72
|
+
}
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def post_response(url, body, content_type = nil)
|
|
76
|
+
uri = URI.parse(url)
|
|
77
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
78
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
79
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
|
80
|
+
request.body = body
|
|
81
|
+
request['Content-Type'] = content_type if content_type
|
|
82
|
+
response = http.request(request)
|
|
83
|
+
headers = {}
|
|
84
|
+
response.each_header { |k, v| headers[k] = v }
|
|
85
|
+
{
|
|
86
|
+
status: response.code.to_i,
|
|
87
|
+
body: response.body,
|
|
88
|
+
headers: headers
|
|
89
|
+
}
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def request(method, url, body = nil, headers = nil)
|
|
93
|
+
uri = URI.parse(url)
|
|
94
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
95
|
+
http.use_ssl = (uri.scheme == 'https')
|
|
96
|
+
|
|
97
|
+
request_class = case method.upcase
|
|
98
|
+
when 'GET' then Net::HTTP::Get
|
|
99
|
+
when 'POST' then Net::HTTP::Post
|
|
100
|
+
when 'PUT' then Net::HTTP::Put
|
|
101
|
+
when 'DELETE' then Net::HTTP::Delete
|
|
102
|
+
when 'PATCH' then Net::HTTP::Patch
|
|
103
|
+
when 'HEAD' then Net::HTTP::Head
|
|
104
|
+
else
|
|
105
|
+
raise ArgumentError, "Unknown HTTP method: #{method}"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
request = request_class.new(uri.request_uri)
|
|
109
|
+
request.body = body if body
|
|
110
|
+
headers&.each { |k, v| request[k] = v }
|
|
111
|
+
|
|
112
|
+
response = http.request(request)
|
|
113
|
+
response_headers = {}
|
|
114
|
+
response.each_header { |k, v| response_headers[k] = v }
|
|
115
|
+
{
|
|
116
|
+
status: response.code.to_i,
|
|
117
|
+
body: response.body,
|
|
118
|
+
headers: response_headers
|
|
119
|
+
}
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
warn "KonpeitoHTTP: Native extension not available, using net/http fallback (#{e.message})"
|
|
125
|
+
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# KonpeitoHTTP - Fast HTTP client using libcurl
|
|
2
|
+
#
|
|
3
|
+
# Usage:
|
|
4
|
+
# # Simple GET (returns body only)
|
|
5
|
+
# body = KonpeitoHTTP.get("https://example.com")
|
|
6
|
+
#
|
|
7
|
+
# # Simple POST (returns body only)
|
|
8
|
+
# body = KonpeitoHTTP.post("https://api.example.com/data", '{"key": "value"}')
|
|
9
|
+
#
|
|
10
|
+
# # GET with full response
|
|
11
|
+
# response = KonpeitoHTTP.get_response("https://example.com")
|
|
12
|
+
# response[:status] # => 200
|
|
13
|
+
# response[:body] # => "<!doctype html>..."
|
|
14
|
+
# response[:headers] # => {"Content-Type" => "text/html", ...}
|
|
15
|
+
#
|
|
16
|
+
# # Generic request with custom headers
|
|
17
|
+
# response = KonpeitoHTTP.request("PUT", "https://api.example.com/resource",
|
|
18
|
+
# '{"data": "value"}',
|
|
19
|
+
# {"Authorization" => "Bearer token"})
|
|
20
|
+
|
|
21
|
+
module KonpeitoHTTP
|
|
22
|
+
# Perform HTTP GET request (simple, returns body only)
|
|
23
|
+
# @param url [String] URL to fetch
|
|
24
|
+
# @return [String] Response body
|
|
25
|
+
# @raise [RuntimeError] if request fails
|
|
26
|
+
def self.get: (String url) -> String
|
|
27
|
+
|
|
28
|
+
# Perform HTTP POST request (simple, returns body only)
|
|
29
|
+
# @param url [String] URL to post to
|
|
30
|
+
# @param body [String] Request body
|
|
31
|
+
# @return [String] Response body
|
|
32
|
+
# @raise [RuntimeError] if request fails
|
|
33
|
+
def self.post: (String url, String body) -> String
|
|
34
|
+
|
|
35
|
+
# Perform HTTP GET request with full response
|
|
36
|
+
# @param url [String] URL to fetch
|
|
37
|
+
# @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
|
|
38
|
+
# @raise [RuntimeError] if request fails
|
|
39
|
+
def self.get_response: (String url) -> Hash[Symbol, untyped]
|
|
40
|
+
|
|
41
|
+
# Perform HTTP POST request with full response
|
|
42
|
+
# @param url [String] URL to post to
|
|
43
|
+
# @param body [String] Request body
|
|
44
|
+
# @param content_type [String?] Content-Type header (optional)
|
|
45
|
+
# @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
|
|
46
|
+
# @raise [RuntimeError] if request fails
|
|
47
|
+
def self.post_response: (String url, String body, String? content_type) -> Hash[Symbol, untyped]
|
|
48
|
+
|
|
49
|
+
# Perform HTTP request with custom method and headers
|
|
50
|
+
# @param method [String] HTTP method (GET, POST, PUT, DELETE, PATCH, HEAD)
|
|
51
|
+
# @param url [String] URL
|
|
52
|
+
# @param body [String?] Request body (optional)
|
|
53
|
+
# @param headers [Hash?] Custom headers (optional)
|
|
54
|
+
# @return [Hash] Response with :status (Integer), :body (String), :headers (Hash)
|
|
55
|
+
# @raise [RuntimeError] if request fails
|
|
56
|
+
def self.request: (String method, String url, String? body, Hash[String, String]? headers) -> Hash[Symbol, untyped]
|
|
57
|
+
end
|