-
Notifications
You must be signed in to change notification settings - Fork 51
Expand file tree
/
Copy pathprocess_env.cpp
More file actions
192 lines (164 loc) · 5.6 KB
/
process_env.cpp
File metadata and controls
192 lines (164 loc) · 5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#include "process_env.h"
#include "extension-api.h"
#include "host_api.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include <cstdio>
namespace builtins::node::process_env {
// Custom proxy handler for environment variables
class EnvProxyHandler : public js::BaseProxyHandler {
public:
EnvProxyHandler() : BaseProxyHandler(nullptr) {}
bool get(JSContext* cx, JS::HandleObject proxy, JS::HandleValue receiver,
JS::HandleId id, JS::MutableHandleValue vp) const override {
// Convert id to string
JS::RootedValue idVal(cx);
if (!JS_IdToValue(cx, id, &idVal) || !idVal.isString()) {
return false;
}
// Convert to UTF8
JS::RootedString idStr(cx, idVal.toString());
JS::UniqueChars propNameUtf8 = JS_EncodeStringToUTF8(cx, idStr);
if (!propNameUtf8) {
return false;
}
// Get all environment variables
auto env_vars = host_api::environment_get_environment();
// Look for the requested environment variable
for (const auto& [key, value] : env_vars) {
if (key == propNameUtf8.get()) {
// Found it! Convert the value to a JS string
JS::RootedString value_str(cx, JS_NewStringCopyZ(cx, value.c_str()));
if (!value_str) {
return false;
}
vp.setString(value_str);
return true;
}
}
// Not found, return undefined
vp.setUndefined();
return true;
}
bool getOwnPropertyDescriptor(JSContext* cx, JS::HandleObject proxy,
JS::HandleId id,
JS::MutableHandle<mozilla::Maybe<JS::PropertyDescriptor>> desc) const override {
// Convert id to string
JS::RootedValue idVal(cx);
if (!JS_IdToValue(cx, id, &idVal) || !idVal.isString()) {
return false;
}
// Convert to UTF8
JS::RootedString idStr(cx, idVal.toString());
JS::UniqueChars propNameUtf8 = JS_EncodeStringToUTF8(cx, idStr);
if (!propNameUtf8) {
return false;
}
// Get all environment variables
auto env_vars = host_api::environment_get_environment();
// Look for the requested environment variable
for (const auto& [key, value] : env_vars) {
if (key == propNameUtf8.get()) {
// Found it! Create a property descriptor
JS::RootedString value_str(cx, JS_NewStringCopyZ(cx, value.c_str()));
if (!value_str) {
return false;
}
desc.set(mozilla::Some(JS::PropertyDescriptor::Data(
JS::StringValue(value_str),
JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT
)));
return true;
}
}
// Not found
desc.set(mozilla::Nothing());
return true;
}
bool defineProperty(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
JS::Handle<JS::PropertyDescriptor> desc,
JS::ObjectOpResult& result) const override {
// Environment variables are read-only
return result.failReadOnly();
}
bool ownPropertyKeys(JSContext* cx, JS::HandleObject proxy,
JS::MutableHandleIdVector props) const override {
// Get all environment variables
auto env_vars = host_api::environment_get_environment();
// Add each environment variable name to the property list
for (const auto& [key, value] : env_vars) {
JS::RootedString key_str(cx, JS_NewStringCopyZ(cx, key.c_str()));
if (!key_str) {
return false;
}
JS::RootedId id(cx);
if (!JS_StringToId(cx, key_str, &id)) {
return false;
}
if (!props.append(id)) {
return false;
}
}
return true;
}
bool delete_(JSContext* cx, JS::HandleObject proxy, JS::HandleId id,
JS::ObjectOpResult& result) const override {
// Environment variables are read-only
return result.failReadOnly();
}
bool preventExtensions(JSContext* cx, JS::HandleObject proxy,
JS::ObjectOpResult& result) const override {
// Environment variables are already non-extensible
return result.succeed();
}
bool isExtensible(JSContext* cx, JS::HandleObject proxy,
bool* extensible) const override {
*extensible = false;
return true;
}
bool getPrototypeIfOrdinary(JSContext* cx, JS::HandleObject proxy,
bool* isOrdinary,
JS::MutableHandleObject protop) const override {
*isOrdinary = true;
protop.set(nullptr);
return true;
}
};
static EnvProxyHandler envProxyHandler;
bool install(api::Engine* engine) {
auto cx = engine->cx();
auto global = engine->global();
// Create process object if it doesn't exist
JS::RootedObject process(cx);
JS::RootedValue process_val(cx);
if (!JS_GetProperty(cx, global, "process", &process_val) || process_val.isUndefined()) {
process = JS_NewPlainObject(cx);
if (!process) {
return false;
}
if (!JS_DefineProperty(cx, global, "process", process, JSPROP_ENUMERATE)) {
return false;
}
} else {
process = &process_val.toObject();
}
// Create the target object (empty object)
JS::RootedObject target(cx, JS_NewPlainObject(cx));
if (!target) {
return false;
}
// Create the proxy with the target object
JS::RootedValue proxyVal(cx);
JS::RootedValue targetVal(cx, JS::ObjectValue(*target));
JS::RootedObject proxy(cx, NewProxyObject(cx, &envProxyHandler, targetVal, nullptr, js::ProxyOptions()));
if (!proxy) {
return false;
}
proxyVal.setObject(*proxy);
// Add env to process
if (!JS_DefineProperty(cx, process, "env", proxyVal, JSPROP_ENUMERATE)) {
return false;
}
return true;
}
} // namespace builtins::node::process_env