1
+ #include " crypto-key.h"
2
+ #include " js-compute-builtins.h"
3
+
4
+ namespace builtins {
5
+
6
+ bool CryptoKey::algorithm_get (JSContext *cx, unsigned argc, JS::Value *vp) {
7
+ METHOD_HEADER (0 );
8
+
9
+ // TODO: Should we move this into the METHOD_HEADER macro?
10
+ // CryptoKey.prototype passes the receiver check in the above macro but is not actually an
11
+ // instance of CryptoKey. We check if `self` is `CryptoKey.prototype` and if it is, we throw a JS
12
+ // Error.
13
+ if (self == proto_obj.get ()) {
14
+ JS_ReportErrorNumberASCII (cx, GetErrorMessageBuiltin, nullptr , JSMSG_INCOMPATIBLE_INSTANCE,
15
+ __func__, CryptoKey::class_.name );
16
+ return false ;
17
+ }
18
+
19
+ auto algorithm = &JS::GetReservedSlot (self, Slots::Algorithm).toObject ();
20
+ JS::RootedObject result (cx, algorithm);
21
+ if (!result) {
22
+ return false ;
23
+ }
24
+ args.rval ().setObject (*result);
25
+
26
+ return true ;
27
+ }
28
+
29
+ bool CryptoKey::extractable_get (JSContext *cx, unsigned argc, JS::Value *vp) {
30
+ METHOD_HEADER (0 );
31
+
32
+ // TODO: Should we move this into the METHOD_HEADER macro?
33
+ // CryptoKey.prototype passes the receiver check in the above macro but is not actually an
34
+ // instance of CryptoKey. We check if `self` is `CryptoKey.prototype` and if it is, we throw a JS
35
+ // Error.
36
+ if (self == proto_obj.get ()) {
37
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_INVALID_INTERFACE,
38
+ " extractable get" , " CryptoKey" );
39
+ return false ;
40
+ }
41
+
42
+ auto extractable = JS::GetReservedSlot (self, Slots::Extractable).toBoolean ();
43
+ args.rval ().setBoolean (extractable);
44
+
45
+ return true ;
46
+ }
47
+
48
+ bool CryptoKey::type_get (JSContext *cx, unsigned argc, JS::Value *vp) {
49
+ METHOD_HEADER (0 )
50
+
51
+ // TODO: Should we move this into the METHOD_HEADER macro?
52
+ // CryptoKey.prototype passes the receiver check in the above macro but is not actually an
53
+ // instance of CryptoKey. We check if `self` is `CryptoKey.prototype` and if it is, we throw a JS
54
+ // Error.
55
+ if (self == proto_obj.get ()) {
56
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_INVALID_INTERFACE, " type get" ,
57
+ " CryptoKey" );
58
+ return false ;
59
+ }
60
+ auto type = static_cast <CryptoKeyType>(JS::GetReservedSlot (self, Slots::Type).toInt32 ());
61
+
62
+ // We store the type internally as a CryptoKeyType variant and need to
63
+ // convert it into it's JSString representation.
64
+ switch (type) {
65
+ case CryptoKeyType::Private: {
66
+ auto str = JS_AtomizeString (cx, " private" );
67
+ if (!str) {
68
+ return false ;
69
+ }
70
+ args.rval ().setString (str);
71
+ return true ;
72
+ }
73
+ case CryptoKeyType::Public: {
74
+ auto str = JS_AtomizeString (cx, " public" );
75
+ if (!str) {
76
+ return false ;
77
+ }
78
+ args.rval ().setString (str);
79
+ return true ;
80
+ }
81
+ case CryptoKeyType::Secret: {
82
+ auto str = JS_AtomizeString (cx, " secret" );
83
+ if (!str) {
84
+ return false ;
85
+ }
86
+ args.rval ().setString (str);
87
+ return true ;
88
+ }
89
+ default : {
90
+ MOZ_ASSERT_UNREACHABLE (" Unknown `CryptoKeyType` value" );
91
+ return false ;
92
+ }
93
+ };
94
+ }
95
+
96
+ bool CryptoKey::usages_get (JSContext *cx, unsigned argc, JS::Value *vp) {
97
+ METHOD_HEADER (0 );
98
+
99
+ // TODO: Should we move this into the METHOD_HEADER macro?
100
+ // CryptoKey.prototype passes the receiver check in the above macro but is not actually an
101
+ // instance of CryptoKey. We check if `self` is `CryptoKey.prototype` and if it is, we throw a JS
102
+ // Error.
103
+ if (self == proto_obj.get ()) {
104
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_INVALID_INTERFACE, " usages get" ,
105
+ " CryptoKey" );
106
+ return false ;
107
+ }
108
+
109
+ // If the JS Array has already been created previously, return it.
110
+ auto cached_usage = JS::GetReservedSlot (self, Slots::UsagesArray);
111
+ if (cached_usage.isObject ()) {
112
+ args.rval ().setObject (cached_usage.toObject ());
113
+ return true ;
114
+ }
115
+ // Else, grab the CryptoKeyUsageBitmap value from Slots::Usages and convert
116
+ // it into a JS Array and store the result in Slots::UsagesArray.
117
+ auto usage = JS::GetReservedSlot (self, Slots::Usages).toInt32 ();
118
+ // The result is ordered alphabetically.
119
+ JS::RootedValueVector result (cx);
120
+ JS::RootedString str (cx);
121
+ auto append = [&](const char *name) -> bool {
122
+ if (!(str = JS_AtomizeString (cx, name))) {
123
+ return false ;
124
+ }
125
+ if (!result.append (JS::StringValue (str))) {
126
+ js::ReportOutOfMemory (cx);
127
+ return false ;
128
+ }
129
+ return true ;
130
+ };
131
+ if (usage & CryptoKeyUsageDecrypt) {
132
+ if (!append (" decrypt" )) {
133
+ return false ;
134
+ }
135
+ }
136
+ if (usage & CryptoKeyUsageDeriveBits) {
137
+ if (!append (" deriveBits" )) {
138
+ return false ;
139
+ }
140
+ }
141
+ if (usage & CryptoKeyUsageDeriveKey) {
142
+ if (!append (" deriveKey" )) {
143
+ return false ;
144
+ }
145
+ }
146
+ if (usage & CryptoKeyUsageEncrypt) {
147
+ if (!append (" encrypt" )) {
148
+ return false ;
149
+ }
150
+ }
151
+ if (usage & CryptoKeyUsageSign) {
152
+ if (!append (" sign" )) {
153
+ return false ;
154
+ }
155
+ }
156
+ if (usage & CryptoKeyUsageUnwrapKey) {
157
+ if (!append (" unwrapKey" )) {
158
+ return false ;
159
+ }
160
+ }
161
+ if (usage & CryptoKeyUsageVerify) {
162
+ if (!append (" verify" )) {
163
+ return false ;
164
+ }
165
+ }
166
+ if (usage & CryptoKeyUsageWrapKey) {
167
+ if (!append (" wrapKey" )) {
168
+ return false ;
169
+ }
170
+ }
171
+
172
+ JS::Rooted<JSObject *> array (cx, JS::NewArrayObject (cx, result));
173
+ if (!array) {
174
+ return false ;
175
+ }
176
+ cached_usage.setObject (*array);
177
+ JS::SetReservedSlot (self, Slots::UsagesArray, cached_usage);
178
+
179
+ args.rval ().setObject (*array);
180
+
181
+ return true ;
182
+ }
183
+
184
+ const JSFunctionSpec CryptoKey::methods[] = {JS_FS_END};
185
+
186
+ const JSPropertySpec CryptoKey::properties[] = {
187
+ JS_PSG (" type" , CryptoKey::type_get, JSPROP_ENUMERATE),
188
+ JS_PSG (" extractable" , CryptoKey::extractable_get, JSPROP_ENUMERATE),
189
+ JS_PSG (" algorithm" , CryptoKey::algorithm_get, JSPROP_ENUMERATE),
190
+ JS_PSG (" usages" , CryptoKey::usages_get, JSPROP_ENUMERATE),
191
+ JS_STRING_SYM_PS (toStringTag, " CryptoKey" , JSPROP_READONLY),
192
+ JS_PS_END};
193
+
194
+ // There is no directly exposed constructor in the CryptoKey interface
195
+ // https://w3c.github.io/webcrypto/#cryptokey-interface We throw a JS Error if the application
196
+ // attempts to call the CryptoKey constructor directly
197
+ bool CryptoKey::constructor (JSContext *cx, unsigned argc, JS::Value *vp) {
198
+ JS_ReportErrorNumberASCII (cx, GetErrorMessage, nullptr , JSMSG_ILLEGAL_CTOR);
199
+ return false ;
200
+ }
201
+
202
+ bool CryptoKey::init_class (JSContext *cx, JS::HandleObject global) {
203
+ return BuiltinImpl<CryptoKey>::init_class_impl (cx, global);
204
+ }
205
+
206
+ } // namespace builtins
0 commit comments