feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
+199
-46
@@ -6,15 +6,17 @@ import (
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"net/url"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/Calcium-Ion/moejs"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/grafana/sobek"
|
||||
)
|
||||
|
||||
type volcSignRequest struct {
|
||||
@@ -29,65 +31,216 @@ type volcSignRequest struct {
|
||||
Timestamp int64 `json:"timestamp"`
|
||||
}
|
||||
|
||||
func injectGlobals(runtime *sobek.Runtime, identity func() string, now func() time.Time, logOutput func(string)) error {
|
||||
// injectGlobals installs utils and console. currentCall returns the hook call
|
||||
// running on runtime, or nil outside one; utils.fetch reads its fetcher and
|
||||
// budget there, so no request data lives in the runtime's globals.
|
||||
func injectGlobals(runtime *moejs.Runtime, identity func() string, now func() time.Time, logOutput func(string), currentCall func() *runtimeCall) error {
|
||||
utils := map[string]any{
|
||||
"hasCapability": HasCapability,
|
||||
"fetch": runtime.Function("fetch", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
call := currentCall()
|
||||
if call == nil {
|
||||
return moejs.Undefined(), fmt.Errorf("utils.fetch is not available outside hooks")
|
||||
}
|
||||
return call.fetch(r, moejs.Arg(args, 0))
|
||||
}),
|
||||
"hasCapability": runtime.Function("hasCapability", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
name, err := stringValue(r, moejs.Arg(args, 0))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.Bool(HasCapability(name)), nil
|
||||
}),
|
||||
"json": map[string]any{
|
||||
"clone": func(call sobek.FunctionCall) sobek.Value {
|
||||
if sobek.IsUndefined(call.Argument(0)) {
|
||||
panic(runtime.NewTypeError("json.clone requires a JSON value"))
|
||||
"clone": runtime.Function("clone", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
if moejs.Arg(args, 0).IsUndefined() {
|
||||
return moejs.Undefined(), r.TypeError("json.clone requires a JSON value")
|
||||
}
|
||||
budget := &jsonStateBudget{ctx: context.Background(), bytes: MaxJSONToolBytes, nodes: maxJSONToolNodes}
|
||||
value, err := newJSONStateNode(call.Argument(0), 0, budget)
|
||||
budget := &jsonStateBudget{ctx: context.Background(), bytes: MaxJSONToolBytes, nodes: maxJSONToolNodes, realm: r}
|
||||
value, err := newJSONStateNode(moejs.Arg(args, 0), 0, budget)
|
||||
if err != nil {
|
||||
panic(runtime.NewTypeError("json.clone: %s", err))
|
||||
var exception *moejs.Exception
|
||||
var interrupted *moejs.InterruptedError
|
||||
if errors.As(err, &exception) || errors.As(err, &interrupted) {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.Undefined(), r.TypeError("json.clone: %s", err)
|
||||
}
|
||||
cloned, err := value.jsValue(runtime)
|
||||
return value.jsValue(r)
|
||||
}),
|
||||
},
|
||||
"unixNow": runtime.Function("unixNow", 0, func(*moejs.Realm, moejs.Value, []moejs.Value) (moejs.Value, error) {
|
||||
return moejs.Int(now().Unix()), nil
|
||||
}),
|
||||
"jwtSignHS256": runtime.Function("jwtSignHS256", 2, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
var claims map[string]any
|
||||
if argument := moejs.Arg(args, 0); !argument.IsNullish() {
|
||||
exported, err := r.ToGoStrict(argument)
|
||||
if err != nil {
|
||||
panic(runtime.NewGoError(err))
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return cloned
|
||||
},
|
||||
},
|
||||
"unixNow": func() int64 { return now().Unix() },
|
||||
"jwtSignHS256": func(claims map[string]any, secret string) (string, error) {
|
||||
return jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims)).SignedString([]byte(secret))
|
||||
},
|
||||
"hmacSHA256": func(message, secret string) string {
|
||||
var ok bool
|
||||
if claims, ok = exported.(map[string]any); !ok {
|
||||
return moejs.Undefined(), r.TypeError("jwtSignHS256 claims must be an object")
|
||||
}
|
||||
}
|
||||
secret, err := stringValue(r, moejs.Arg(args, 1))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
token, err := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims(claims)).SignedString([]byte(secret))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.String(token), nil
|
||||
}),
|
||||
"hmacSHA256": runtime.Function("hmacSHA256", 2, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
message, err := stringValue(r, moejs.Arg(args, 0))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
secret, err := stringValue(r, moejs.Arg(args, 1))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
mac := hmac.New(sha256.New, []byte(secret))
|
||||
_, _ = mac.Write([]byte(message))
|
||||
return hex.EncodeToString(mac.Sum(nil))
|
||||
},
|
||||
"base64": func(value string) string { return base64.StdEncoding.EncodeToString([]byte(value)) },
|
||||
"base64URL": func(value string) string {
|
||||
return base64.RawURLEncoding.EncodeToString([]byte(value))
|
||||
},
|
||||
"base64URLDecode": func(value string) (string, error) {
|
||||
return moejs.String(hex.EncodeToString(mac.Sum(nil))), nil
|
||||
}),
|
||||
"base64": runtime.Function("base64", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
value, err := stringValue(r, moejs.Arg(args, 0))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.String(base64.StdEncoding.EncodeToString([]byte(value))), nil
|
||||
}),
|
||||
"base64URL": runtime.Function("base64URL", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
value, err := stringValue(r, moejs.Arg(args, 0))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.String(base64.RawURLEncoding.EncodeToString([]byte(value))), nil
|
||||
}),
|
||||
"base64URLDecode": runtime.Function("base64URLDecode", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
value, err := stringValue(r, moejs.Arg(args, 0))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
decoded, err := base64.RawURLEncoding.DecodeString(value)
|
||||
return string(decoded), err
|
||||
},
|
||||
"uuid": func() string { return uuid.NewString() },
|
||||
"volcSignV4": func(request volcSignRequest) (map[string]string, error) {
|
||||
return signVolcV4(request, now)
|
||||
},
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return moejs.String(string(decoded)), nil
|
||||
}),
|
||||
"uuid": runtime.Function("uuid", 0, func(*moejs.Realm, moejs.Value, []moejs.Value) (moejs.Value, error) {
|
||||
return moejs.String(uuid.NewString()), nil
|
||||
}),
|
||||
"volcSignV4": runtime.Function("volcSignV4", 1, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
// Fields are read by their Go names, as plugins have always
|
||||
// passed them.
|
||||
var request volcSignRequest
|
||||
argument := moejs.Arg(args, 0)
|
||||
if !argument.IsNullish() && !argument.IsObject() {
|
||||
return moejs.Undefined(), r.TypeError("volcSignV4 request must be an object")
|
||||
}
|
||||
if argument.IsObject() {
|
||||
object := argument.AsObject()
|
||||
fields := []struct {
|
||||
name string
|
||||
target *string
|
||||
}{
|
||||
{"Method", &request.Method}, {"URL", &request.URL}, {"Body", &request.Body},
|
||||
{"AccessKey", &request.AccessKey}, {"SecretKey", &request.SecretKey},
|
||||
{"Region", &request.Region}, {"Service", &request.Service},
|
||||
}
|
||||
for _, field := range fields {
|
||||
value, err := object.GetProp(r, r.KeyFromGoString(field.name))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
if *field.target, err = stringValue(r, value); err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
}
|
||||
headers, err := object.GetProp(r, r.KeyFromGoString("Headers"))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
if headers.IsObject() {
|
||||
keys, err := r.EnumerableOwnKeys(headers.AsObject())
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
request.Headers = make(map[string]string, len(keys))
|
||||
for _, key := range keys {
|
||||
value, err := headers.AsObject().GetProp(r, key)
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
if request.Headers[key.GoString()], err = stringValue(r, value); err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
}
|
||||
}
|
||||
timestamp, err := object.GetProp(r, r.KeyFromGoString("Timestamp"))
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
if !timestamp.IsNullish() {
|
||||
seconds, err := r.ToNumber(timestamp)
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
if !math.IsNaN(seconds) && !math.IsInf(seconds, 0) {
|
||||
request.Timestamp = int64(seconds)
|
||||
}
|
||||
}
|
||||
}
|
||||
signed, err := signVolcV4(request, now)
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
return r.FromGo(signed)
|
||||
}),
|
||||
}
|
||||
if err := runtime.Set("utils", utils); err != nil {
|
||||
if err := runtime.SetGlobal("utils", utils); err != nil {
|
||||
return err
|
||||
}
|
||||
console := runtime.NewObject()
|
||||
if err := console.Set("log", func(call sobek.FunctionCall) sobek.Value {
|
||||
parts := make([]string, len(call.Arguments))
|
||||
for i, argument := range call.Arguments {
|
||||
parts[i] = argument.String()
|
||||
}
|
||||
if logOutput != nil {
|
||||
logOutput(identity() + " " + strings.Join(parts, " "))
|
||||
}
|
||||
return sobek.Undefined()
|
||||
}); err != nil {
|
||||
return err
|
||||
return runtime.SetGlobal("console", map[string]any{
|
||||
"log": runtime.Function("log", 0, func(r *moejs.Realm, _ moejs.Value, args []moejs.Value) (moejs.Value, error) {
|
||||
parts := make([]string, len(args))
|
||||
for i, argument := range args {
|
||||
if argument.IsSymbol() {
|
||||
parts[i] = argument.String()
|
||||
continue
|
||||
}
|
||||
text, err := r.ToString(argument)
|
||||
if err != nil {
|
||||
return moejs.Undefined(), err
|
||||
}
|
||||
parts[i] = text.GoString()
|
||||
}
|
||||
if logOutput != nil {
|
||||
logOutput(identity() + " " + strings.Join(parts, " "))
|
||||
}
|
||||
return moejs.Undefined(), nil
|
||||
}),
|
||||
})
|
||||
}
|
||||
|
||||
// stringValue reads a host function's string parameter: undefined and null
|
||||
// read as "", other values as JavaScript's String(value).
|
||||
func stringValue(r *moejs.Realm, value moejs.Value) (string, error) {
|
||||
if value.IsNullish() {
|
||||
return "", nil
|
||||
}
|
||||
return runtime.Set("console", console)
|
||||
if value.IsString() {
|
||||
return value.AsString().GoString(), nil
|
||||
}
|
||||
text, err := r.ToString(value)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return text.GoString(), nil
|
||||
}
|
||||
|
||||
func signVolcV4(request volcSignRequest, now func() time.Time) (map[string]string, error) {
|
||||
|
||||
Reference in new issue
Block a user