Closer file structure to desired
This commit is contained in:
74
lib/challenge/generic.go
Normal file
74
lib/challenge/generic.go
Normal file
@@ -0,0 +1,74 @@
|
||||
//go:build !tinygo
|
||||
|
||||
package challenge
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"github.com/tetratelabs/wazero/api"
|
||||
)
|
||||
|
||||
func MakeChallengeCall(ctx context.Context, mod api.Module, in MakeChallengeInput) (*MakeChallengeOutput, error) {
|
||||
makeChallengeFunc := mod.ExportedFunction("MakeChallenge")
|
||||
malloc := mod.ExportedFunction("malloc")
|
||||
free := mod.ExportedFunction("free")
|
||||
|
||||
inData, err := json.Marshal(in)
|
||||
|
||||
mallocResult, err := malloc.Call(ctx, uint64(len(inData)))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer free.Call(ctx, mallocResult[0])
|
||||
if !mod.Memory().Write(uint32(mallocResult[0]), inData) {
|
||||
return nil, errors.New("could not write memory")
|
||||
}
|
||||
result, err := makeChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData)))))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resultPtr := Allocation(result[0])
|
||||
outData, ok := mod.Memory().Read(resultPtr.Pointer(), resultPtr.Size())
|
||||
if !ok {
|
||||
return nil, errors.New("could not read result")
|
||||
}
|
||||
defer free.Call(ctx, uint64(resultPtr.Pointer()))
|
||||
|
||||
var out MakeChallengeOutput
|
||||
err = json.Unmarshal(outData, &out)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &out, nil
|
||||
}
|
||||
|
||||
func VerifyChallengeCall(ctx context.Context, mod api.Module, in VerifyChallengeInput) (VerifyChallengeOutput, error) {
|
||||
verifyChallengeFunc := mod.ExportedFunction("VerifyChallenge")
|
||||
malloc := mod.ExportedFunction("malloc")
|
||||
free := mod.ExportedFunction("free")
|
||||
|
||||
inData, err := json.Marshal(in)
|
||||
|
||||
mallocResult, err := malloc.Call(ctx, uint64(len(inData)))
|
||||
if err != nil {
|
||||
return VerifyChallengeOutputError, err
|
||||
}
|
||||
defer free.Call(ctx, mallocResult[0])
|
||||
if !mod.Memory().Write(uint32(mallocResult[0]), inData) {
|
||||
return VerifyChallengeOutputError, errors.New("could not write memory")
|
||||
}
|
||||
result, err := verifyChallengeFunc.Call(ctx, uint64(NewAllocation(uint32(mallocResult[0]), uint32(len(inData)))))
|
||||
if err != nil {
|
||||
return VerifyChallengeOutputError, err
|
||||
}
|
||||
|
||||
return VerifyChallengeOutput(result[0]), nil
|
||||
}
|
||||
|
||||
func PtrToBytes(ptr uint32, size uint32) []byte { panic("not implemented") }
|
||||
func BytesToPtr(s []byte) (uint32, uint32) { panic("not implemented") }
|
||||
func BytesToLeakedPtr(s []byte) (uint32, uint32) { panic("not implemented") }
|
||||
func PtrToString(ptr uint32, size uint32) string { panic("not implemented") }
|
||||
func StringToPtr(s string) (uint32, uint32) { panic("not implemented") }
|
||||
func StringToLeakedPtr(s string) (uint32, uint32) { panic("not implemented") }
|
95
lib/challenge/inline/hex.go
Normal file
95
lib/challenge/inline/hex.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package inline
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
const (
|
||||
hextable = "0123456789abcdef"
|
||||
reverseHexTable = "" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\x0a\x0b\x0c\x0d\x0e\x0f\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" +
|
||||
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
|
||||
)
|
||||
|
||||
// EncodedLen returns the length of an encoding of n source bytes.
|
||||
// Specifically, it returns n * 2.
|
||||
func EncodedLen(n int) int { return n * 2 }
|
||||
|
||||
// Encode encodes src into [EncodedLen](len(src))
|
||||
// bytes of dst. As a convenience, it returns the number
|
||||
// of bytes written to dst, but this value is always [EncodedLen](len(src)).
|
||||
// Encode implements hexadecimal encoding.
|
||||
func Encode(dst, src []byte) int {
|
||||
j := 0
|
||||
for _, v := range src {
|
||||
dst[j] = hextable[v>>4]
|
||||
dst[j+1] = hextable[v&0x0f]
|
||||
j += 2
|
||||
}
|
||||
return len(src) * 2
|
||||
}
|
||||
|
||||
// ErrLength reports an attempt to decode an odd-length input
|
||||
// using [Decode] or [DecodeString].
|
||||
// The stream-based Decoder returns [io.ErrUnexpectedEOF] instead of ErrLength.
|
||||
var ErrLength = errors.New("encoding/hex: odd length hex string")
|
||||
|
||||
// InvalidByteError values describe errors resulting from an invalid byte in a hex string.
|
||||
type InvalidByteError byte
|
||||
|
||||
func (e InvalidByteError) Error() string {
|
||||
return "encoding/hex: invalid byte"
|
||||
}
|
||||
|
||||
// DecodedLen returns the length of a decoding of x source bytes.
|
||||
// Specifically, it returns x / 2.
|
||||
func DecodedLen(x int) int { return x / 2 }
|
||||
|
||||
// Decode decodes src into [DecodedLen](len(src)) bytes,
|
||||
// returning the actual number of bytes written to dst.
|
||||
//
|
||||
// Decode expects that src contains only hexadecimal
|
||||
// characters and that src has even length.
|
||||
// If the input is malformed, Decode returns the number
|
||||
// of bytes decoded before the error.
|
||||
func Decode(dst, src []byte) (int, error) {
|
||||
i, j := 0, 1
|
||||
for ; j < len(src); j += 2 {
|
||||
p := src[j-1]
|
||||
q := src[j]
|
||||
|
||||
a := reverseHexTable[p]
|
||||
b := reverseHexTable[q]
|
||||
if a > 0x0f {
|
||||
return i, InvalidByteError(p)
|
||||
}
|
||||
if b > 0x0f {
|
||||
return i, InvalidByteError(q)
|
||||
}
|
||||
dst[i] = (a << 4) | b
|
||||
i++
|
||||
}
|
||||
if len(src)%2 == 1 {
|
||||
// Check for invalid char before reporting bad length,
|
||||
// since the invalid char (if present) is an earlier problem.
|
||||
if reverseHexTable[src[j-1]] > 0x0f {
|
||||
return i, InvalidByteError(src[j-1])
|
||||
}
|
||||
return i, ErrLength
|
||||
}
|
||||
return i, nil
|
||||
}
|
234
lib/challenge/inline/mime.go
Normal file
234
lib/challenge/inline/mime.go
Normal file
@@ -0,0 +1,234 @@
|
||||
package inline
|
||||
|
||||
// from textproto
|
||||
|
||||
// A MIMEHeader represents a MIME-style header mapping
|
||||
// keys to sets of values.
|
||||
type MIMEHeader map[string][]string
|
||||
|
||||
// Add adds the key, value pair to the header.
|
||||
// It appends to any existing values associated with key.
|
||||
func (h MIMEHeader) Add(key, value string) {
|
||||
key = CanonicalMIMEHeaderKey(key)
|
||||
h[key] = append(h[key], value)
|
||||
}
|
||||
|
||||
// Set sets the header entries associated with key to
|
||||
// the single element value. It replaces any existing
|
||||
// values associated with key.
|
||||
func (h MIMEHeader) Set(key, value string) {
|
||||
h[CanonicalMIMEHeaderKey(key)] = []string{value}
|
||||
}
|
||||
|
||||
// Get gets the first value associated with the given key.
|
||||
// It is case insensitive; [CanonicalMIMEHeaderKey] is used
|
||||
// to canonicalize the provided key.
|
||||
// If there are no values associated with the key, Get returns "".
|
||||
// To use non-canonical keys, access the map directly.
|
||||
func (h MIMEHeader) Get(key string) string {
|
||||
if h == nil {
|
||||
return ""
|
||||
}
|
||||
v := h[CanonicalMIMEHeaderKey(key)]
|
||||
if len(v) == 0 {
|
||||
return ""
|
||||
}
|
||||
return v[0]
|
||||
}
|
||||
|
||||
// Values returns all values associated with the given key.
|
||||
// It is case insensitive; [CanonicalMIMEHeaderKey] is
|
||||
// used to canonicalize the provided key. To use non-canonical
|
||||
// keys, access the map directly.
|
||||
// The returned slice is not a copy.
|
||||
func (h MIMEHeader) Values(key string) []string {
|
||||
if h == nil {
|
||||
return nil
|
||||
}
|
||||
return h[CanonicalMIMEHeaderKey(key)]
|
||||
}
|
||||
|
||||
// Del deletes the values associated with key.
|
||||
func (h MIMEHeader) Del(key string) {
|
||||
delete(h, CanonicalMIMEHeaderKey(key))
|
||||
}
|
||||
|
||||
// CanonicalMIMEHeaderKey returns the canonical format of the
|
||||
// MIME header key s. The canonicalization converts the first
|
||||
// letter and any letter following a hyphen to upper case;
|
||||
// the rest are converted to lowercase. For example, the
|
||||
// canonical key for "accept-encoding" is "Accept-Encoding".
|
||||
// MIME header keys are assumed to be ASCII only.
|
||||
// If s contains a space or invalid header field bytes, it is
|
||||
// returned without modifications.
|
||||
func CanonicalMIMEHeaderKey(s string) string {
|
||||
// Quick check for canonical encoding.
|
||||
upper := true
|
||||
for i := 0; i < len(s); i++ {
|
||||
c := s[i]
|
||||
if !validHeaderFieldByte(c) {
|
||||
return s
|
||||
}
|
||||
if upper && 'a' <= c && c <= 'z' {
|
||||
s, _ = canonicalMIMEHeaderKey([]byte(s))
|
||||
return s
|
||||
}
|
||||
if !upper && 'A' <= c && c <= 'Z' {
|
||||
s, _ = canonicalMIMEHeaderKey([]byte(s))
|
||||
return s
|
||||
}
|
||||
upper = c == '-'
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
const toLower = 'a' - 'A'
|
||||
|
||||
// validHeaderFieldByte reports whether c is a valid byte in a header
|
||||
// field name. RFC 7230 says:
|
||||
//
|
||||
// header-field = field-name ":" OWS field-value OWS
|
||||
// field-name = token
|
||||
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||
// "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
|
||||
// token = 1*tchar
|
||||
func validHeaderFieldByte(c byte) bool {
|
||||
// mask is a 128-bit bitmap with 1s for allowed bytes,
|
||||
// so that the byte c can be tested with a shift and an and.
|
||||
// If c >= 128, then 1<<c and 1<<(c-64) will both be zero,
|
||||
// and this function will return false.
|
||||
const mask = 0 |
|
||||
(1<<(10)-1)<<'0' |
|
||||
(1<<(26)-1)<<'a' |
|
||||
(1<<(26)-1)<<'A' |
|
||||
1<<'!' |
|
||||
1<<'#' |
|
||||
1<<'$' |
|
||||
1<<'%' |
|
||||
1<<'&' |
|
||||
1<<'\'' |
|
||||
1<<'*' |
|
||||
1<<'+' |
|
||||
1<<'-' |
|
||||
1<<'.' |
|
||||
1<<'^' |
|
||||
1<<'_' |
|
||||
1<<'`' |
|
||||
1<<'|' |
|
||||
1<<'~'
|
||||
return ((uint64(1)<<c)&(mask&(1<<64-1)) |
|
||||
(uint64(1)<<(c-64))&(mask>>64)) != 0
|
||||
}
|
||||
|
||||
// canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
|
||||
// allowed to mutate the provided byte slice before returning the
|
||||
// string.
|
||||
//
|
||||
// For invalid inputs (if a contains spaces or non-token bytes), a
|
||||
// is unchanged and a string copy is returned.
|
||||
//
|
||||
// ok is true if the header key contains only valid characters and spaces.
|
||||
// ReadMIMEHeader accepts header keys containing spaces, but does not
|
||||
// canonicalize them.
|
||||
func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) {
|
||||
if len(a) == 0 {
|
||||
return "", false
|
||||
}
|
||||
|
||||
// See if a looks like a header key. If not, return it unchanged.
|
||||
noCanon := false
|
||||
for _, c := range a {
|
||||
if validHeaderFieldByte(c) {
|
||||
continue
|
||||
}
|
||||
// Don't canonicalize.
|
||||
if c == ' ' {
|
||||
// We accept invalid headers with a space before the
|
||||
// colon, but must not canonicalize them.
|
||||
// See https://go.dev/issue/34540.
|
||||
noCanon = true
|
||||
continue
|
||||
}
|
||||
return string(a), false
|
||||
}
|
||||
if noCanon {
|
||||
return string(a), true
|
||||
}
|
||||
|
||||
upper := true
|
||||
for i, c := range a {
|
||||
// Canonicalize: first letter upper case
|
||||
// and upper case after each dash.
|
||||
// (Host, User-Agent, If-Modified-Since).
|
||||
// MIME headers are ASCII only, so no Unicode issues.
|
||||
if upper && 'a' <= c && c <= 'z' {
|
||||
c -= toLower
|
||||
} else if !upper && 'A' <= c && c <= 'Z' {
|
||||
c += toLower
|
||||
}
|
||||
a[i] = c
|
||||
upper = c == '-' // for next time
|
||||
}
|
||||
|
||||
// The compiler recognizes m[string(byteSlice)] as a special
|
||||
// case, so a copy of a's bytes into a new string does not
|
||||
// happen in this map lookup:
|
||||
if v := commonHeader[string(a)]; v != "" {
|
||||
return v, true
|
||||
}
|
||||
return string(a), true
|
||||
}
|
||||
|
||||
func init() {
|
||||
initCommonHeader()
|
||||
}
|
||||
|
||||
// commonHeader interns common header strings.
|
||||
var commonHeader map[string]string
|
||||
|
||||
func initCommonHeader() {
|
||||
commonHeader = make(map[string]string)
|
||||
for _, v := range []string{
|
||||
"Accept",
|
||||
"Accept-Charset",
|
||||
"Accept-Encoding",
|
||||
"Accept-Language",
|
||||
"Accept-Ranges",
|
||||
"Cache-Control",
|
||||
"Cc",
|
||||
"Connection",
|
||||
"Content-Id",
|
||||
"Content-Language",
|
||||
"Content-Length",
|
||||
"Content-Transfer-Encoding",
|
||||
"Content-Type",
|
||||
"Cookie",
|
||||
"Date",
|
||||
"Dkim-Signature",
|
||||
"Etag",
|
||||
"Expires",
|
||||
"From",
|
||||
"Host",
|
||||
"If-Modified-Since",
|
||||
"If-None-Match",
|
||||
"In-Reply-To",
|
||||
"Last-Modified",
|
||||
"Location",
|
||||
"Message-Id",
|
||||
"Mime-Version",
|
||||
"Pragma",
|
||||
"Received",
|
||||
"Return-Path",
|
||||
"Server",
|
||||
"Set-Cookie",
|
||||
"Subject",
|
||||
"To",
|
||||
"User-Agent",
|
||||
"Via",
|
||||
"X-Forwarded-For",
|
||||
"X-Imforwards",
|
||||
"X-Powered-By",
|
||||
} {
|
||||
commonHeader[v] = v
|
||||
}
|
||||
}
|
119
lib/challenge/interface.go
Normal file
119
lib/challenge/interface.go
Normal file
@@ -0,0 +1,119 @@
|
||||
package challenge
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"git.gammaspectra.live/git/go-away/lib/challenge/inline"
|
||||
)
|
||||
|
||||
type MakeChallenge func(in Allocation) (out Allocation)
|
||||
|
||||
type Allocation uint64
|
||||
|
||||
func NewAllocation(ptr, size uint32) Allocation {
|
||||
return Allocation((uint64(ptr) << uint64(32)) | uint64(size))
|
||||
}
|
||||
|
||||
func (p Allocation) Pointer() uint32 {
|
||||
return uint32(p >> 32)
|
||||
}
|
||||
func (p Allocation) Size() uint32 {
|
||||
return uint32(p)
|
||||
}
|
||||
|
||||
func MakeChallengeDecode(callback func(in MakeChallengeInput, out *MakeChallengeOutput), in Allocation) (out Allocation) {
|
||||
outStruct := &MakeChallengeOutput{}
|
||||
var inStruct MakeChallengeInput
|
||||
|
||||
inData := PtrToBytes(in.Pointer(), in.Size())
|
||||
|
||||
err := json.Unmarshal(inData, &inStruct)
|
||||
if err != nil {
|
||||
outStruct.Code = 500
|
||||
outStruct.Error = err.Error()
|
||||
} else {
|
||||
outStruct.Code = 200
|
||||
outStruct.Headers = make(inline.MIMEHeader)
|
||||
|
||||
func() {
|
||||
// encapsulate err
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
if outStruct.Code == 200 {
|
||||
outStruct.Code = 500
|
||||
}
|
||||
if err, ok := recovered.(error); ok {
|
||||
outStruct.Error = err.Error()
|
||||
} else {
|
||||
outStruct.Error = "error"
|
||||
}
|
||||
}
|
||||
}()
|
||||
callback(inStruct, outStruct)
|
||||
}()
|
||||
}
|
||||
|
||||
if len(outStruct.Headers) == 0 {
|
||||
outStruct.Headers = nil
|
||||
}
|
||||
|
||||
outData, err := json.Marshal(outStruct)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return NewAllocation(BytesToLeakedPtr(outData))
|
||||
}
|
||||
|
||||
func VerifyChallengeDecode(callback func(in VerifyChallengeInput) VerifyChallengeOutput, in Allocation) (out VerifyChallengeOutput) {
|
||||
var inStruct VerifyChallengeInput
|
||||
|
||||
inData := PtrToBytes(in.Pointer(), in.Size())
|
||||
|
||||
err := json.Unmarshal(inData, &inStruct)
|
||||
if err != nil {
|
||||
return VerifyChallengeOutputError
|
||||
} else {
|
||||
func() {
|
||||
// encapsulate err
|
||||
defer func() {
|
||||
if recovered := recover(); recovered != nil {
|
||||
out = VerifyChallengeOutputError
|
||||
}
|
||||
}()
|
||||
out = callback(inStruct)
|
||||
}()
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
type MakeChallengeInput struct {
|
||||
Key []byte
|
||||
|
||||
Parameters map[string]string
|
||||
|
||||
Headers inline.MIMEHeader
|
||||
Data []byte
|
||||
}
|
||||
|
||||
type MakeChallengeOutput struct {
|
||||
Data []byte
|
||||
Code int
|
||||
Headers inline.MIMEHeader
|
||||
Error string
|
||||
}
|
||||
|
||||
type VerifyChallengeInput struct {
|
||||
Key []byte
|
||||
Parameters map[string]string
|
||||
|
||||
Result []byte
|
||||
}
|
||||
|
||||
type VerifyChallengeOutput uint64
|
||||
|
||||
const (
|
||||
VerifyChallengeOutputOK = VerifyChallengeOutput(iota)
|
||||
VerifyChallengeOutputFailed
|
||||
VerifyChallengeOutputError
|
||||
)
|
59
lib/challenge/tinygo.go
Normal file
59
lib/challenge/tinygo.go
Normal file
@@ -0,0 +1,59 @@
|
||||
//go:build tinygo
|
||||
|
||||
package challenge
|
||||
|
||||
// #include <stdlib.h>
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// PtrToBytes returns a byte slice from WebAssembly compatible numeric types
|
||||
// representing its pointer and length.
|
||||
func PtrToBytes(ptr uint32, size uint32) []byte {
|
||||
return unsafe.Slice((*byte)(unsafe.Pointer(uintptr(ptr))), size)
|
||||
}
|
||||
|
||||
// BytesToPtr returns a pointer and size pair for the given byte slice in a way
|
||||
// compatible with WebAssembly numeric types.
|
||||
// The returned pointer aliases the slice hence the slice must be kept alive
|
||||
// until ptr is no longer needed.
|
||||
func BytesToPtr(s []byte) (uint32, uint32) {
|
||||
ptr := unsafe.Pointer(unsafe.SliceData(s))
|
||||
return uint32(uintptr(ptr)), uint32(len(s))
|
||||
}
|
||||
|
||||
// BytesToLeakedPtr returns a pointer and size pair for the given byte slice in a way
|
||||
// compatible with WebAssembly numeric types.
|
||||
// The pointer is not automatically managed by TinyGo hence it must be freed by the host.
|
||||
func BytesToLeakedPtr(s []byte) (uint32, uint32) {
|
||||
size := C.ulong(len(s))
|
||||
ptr := unsafe.Pointer(C.malloc(size))
|
||||
copy(unsafe.Slice((*byte)(ptr), size), s)
|
||||
return uint32(uintptr(ptr)), uint32(size)
|
||||
}
|
||||
|
||||
// PtrToString returns a string from WebAssembly compatible numeric types
|
||||
// representing its pointer and length.
|
||||
func PtrToString(ptr uint32, size uint32) string {
|
||||
return unsafe.String((*byte)(unsafe.Pointer(uintptr(ptr))), size)
|
||||
}
|
||||
|
||||
// StringToPtr returns a pointer and size pair for the given string in a way
|
||||
// compatible with WebAssembly numeric types.
|
||||
// The returned pointer aliases the string hence the string must be kept alive
|
||||
// until ptr is no longer needed.
|
||||
func StringToPtr(s string) (uint32, uint32) {
|
||||
ptr := unsafe.Pointer(unsafe.StringData(s))
|
||||
return uint32(uintptr(ptr)), uint32(len(s))
|
||||
}
|
||||
|
||||
// StringToLeakedPtr returns a pointer and size pair for the given string in a way
|
||||
// compatible with WebAssembly numeric types.
|
||||
// The pointer is not automatically managed by TinyGo hence it must be freed by the host.
|
||||
func StringToLeakedPtr(s string) (uint32, uint32) {
|
||||
size := C.ulong(len(s))
|
||||
ptr := unsafe.Pointer(C.malloc(size))
|
||||
copy(unsafe.Slice((*byte)(ptr), size), s)
|
||||
return uint32(uintptr(ptr)), uint32(size)
|
||||
}
|
@@ -9,7 +9,7 @@ import (
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
go_away "git.gammaspectra.live/git/go-away"
|
||||
"git.gammaspectra.live/git/go-away/embed"
|
||||
"git.gammaspectra.live/git/go-away/lib/network"
|
||||
"git.gammaspectra.live/git/go-away/lib/policy"
|
||||
"github.com/google/cel-go/common/types"
|
||||
@@ -43,7 +43,7 @@ func init() {
|
||||
|
||||
templates = make(map[string]*template.Template)
|
||||
|
||||
dir, err := go_away.TemplatesFs.ReadDir("templates")
|
||||
dir, err := embed.TemplatesFs.ReadDir("templates")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -51,7 +51,7 @@ func init() {
|
||||
if e.IsDir() {
|
||||
continue
|
||||
}
|
||||
data, err := go_away.TemplatesFs.ReadFile(filepath.Join("templates", e.Name()))
|
||||
data, err := embed.TemplatesFs.ReadFile(filepath.Join("templates", e.Name()))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@@ -373,7 +373,7 @@ func (state *State) setupRoutes() error {
|
||||
|
||||
state.Mux.HandleFunc("/", state.handleRequest)
|
||||
|
||||
state.Mux.Handle("GET "+state.UrlPath+"/assets/", http.StripPrefix(state.UrlPath, gzipped.FileServer(gzipped.FS(go_away.AssetsFs))))
|
||||
state.Mux.Handle("GET "+state.UrlPath+"/assets/", http.StripPrefix(state.UrlPath, gzipped.FileServer(gzipped.FS(embed.AssetsFs))))
|
||||
|
||||
for challengeName, c := range state.Challenges {
|
||||
if c.Static != nil {
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
go_away "git.gammaspectra.live/git/go-away"
|
||||
"git.gammaspectra.live/git/go-away/embed"
|
||||
"io"
|
||||
"path"
|
||||
"slices"
|
||||
@@ -17,7 +17,7 @@ func (state *State) getPoison(mime string, encodings []string) (r io.ReadCloser,
|
||||
}
|
||||
|
||||
p := path.Join("poison", strings.ReplaceAll(mime, "/", "_")+"."+encoding+".poison")
|
||||
f, err := go_away.PoisonFs.Open(p)
|
||||
f, err := embed.PoisonFs.Open(p)
|
||||
if err == nil {
|
||||
return f, encoding
|
||||
}
|
||||
|
26
lib/state.go
26
lib/state.go
@@ -11,9 +11,9 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
go_away "git.gammaspectra.live/git/go-away"
|
||||
"git.gammaspectra.live/git/go-away/challenge"
|
||||
"git.gammaspectra.live/git/go-away/challenge/inline"
|
||||
"git.gammaspectra.live/git/go-away/embed"
|
||||
challenge2 "git.gammaspectra.live/git/go-away/lib/challenge"
|
||||
"git.gammaspectra.live/git/go-away/lib/challenge/inline"
|
||||
"git.gammaspectra.live/git/go-away/lib/condition"
|
||||
"git.gammaspectra.live/git/go-away/lib/policy"
|
||||
"github.com/google/cel-go/cel"
|
||||
@@ -101,7 +101,7 @@ type ChallengeState struct {
|
||||
|
||||
type StateSettings struct {
|
||||
Debug bool
|
||||
PackagePath string
|
||||
PackageName string
|
||||
ChallengeTemplate string
|
||||
ChallengeTemplateTheme string
|
||||
}
|
||||
@@ -114,7 +114,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
return http.ErrUseLastResponse
|
||||
},
|
||||
}
|
||||
state.UrlPath = "/.well-known/." + state.Settings.PackagePath
|
||||
state.UrlPath = "/.well-known/." + state.Settings.PackageName
|
||||
|
||||
state.Backends = make(map[string]http.Handler)
|
||||
|
||||
@@ -198,7 +198,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
}
|
||||
|
||||
assetPath := c.Path + "/static/"
|
||||
subFs, err := fs.Sub(go_away.ChallengeFs, fmt.Sprintf("challenge/%s/static", challengeName))
|
||||
subFs, err := fs.Sub(embed.ChallengeFs, fmt.Sprintf("challenge/%s/static", challengeName))
|
||||
if err == nil {
|
||||
c.Static = http.StripPrefix(
|
||||
assetPath,
|
||||
@@ -458,7 +458,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
})
|
||||
|
||||
case "wasm":
|
||||
wasmData, err := go_away.ChallengeFs.ReadFile(fmt.Sprintf("challenge/%s/runtime/%s", challengeName, p.Runtime.Asset))
|
||||
wasmData, err := embed.ChallengeFs.ReadFile(fmt.Sprintf("challenge/%s/runtime/%s", challengeName, p.Runtime.Asset))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("c %s: could not load runtime: %w", challengeName, err)
|
||||
}
|
||||
@@ -470,7 +470,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
c.MakeChallenge = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
err := state.ChallengeMod(challengeName, func(ctx context.Context, mod api.Module) (err error) {
|
||||
|
||||
in := challenge.MakeChallengeInput{
|
||||
in := challenge2.MakeChallengeInput{
|
||||
Key: state.GetChallengeKeyForRequest(challengeName, time.Now().UTC().Add(DefaultValidity).Round(DefaultValidity), r),
|
||||
Parameters: p.Parameters,
|
||||
Headers: inline.MIMEHeader(r.Header),
|
||||
@@ -480,7 +480,7 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
return err
|
||||
}
|
||||
|
||||
out, err := challenge.MakeChallengeCall(state.WasmContext, mod, in)
|
||||
out, err := challenge2.MakeChallengeCall(state.WasmContext, mod, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -502,21 +502,21 @@ func NewState(p policy.Policy, settings StateSettings) (state *State, err error)
|
||||
|
||||
c.Verify = func(key []byte, result string) (ok bool, err error) {
|
||||
err = state.ChallengeMod(challengeName, func(ctx context.Context, mod api.Module) (err error) {
|
||||
in := challenge.VerifyChallengeInput{
|
||||
in := challenge2.VerifyChallengeInput{
|
||||
Key: key,
|
||||
Parameters: p.Parameters,
|
||||
Result: []byte(result),
|
||||
}
|
||||
|
||||
out, err := challenge.VerifyChallengeCall(state.WasmContext, mod, in)
|
||||
out, err := challenge2.VerifyChallengeCall(state.WasmContext, mod, in)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if out == challenge.VerifyChallengeOutputError {
|
||||
if out == challenge2.VerifyChallengeOutputError {
|
||||
return errors.New("error checking challenge")
|
||||
}
|
||||
ok = out == challenge.VerifyChallengeOutputOK
|
||||
ok = out == challenge2.VerifyChallengeOutputOK
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
|
Reference in New Issue
Block a user