Solved

How to verify the caller and contents in typescript based Shopify Function(restrictions due to Javy)

sriram-1
Shopify Partner
6 0 1

I'm writing a shopify function for applying discounts to the cart items. I want to send some data through the cart attributes to the shopify function which involves a RSA signature of the cart items using a private key. I want to verify this signature in the Shopify function using the public key. I'm implementing this function in typescript. Started with jsonwebtoken library before I understood it does not work with Javy runtime. Javy runtime from Shopify converts the corresponding javascript (from typescript) into webassembly (.wasm). Javy runtime has restrictions - for example, I'm not able to use any of the node native crypto modules. I can't use any library that has async/await model, can't use functions like atob, Buffer etc due to Javy restrictions. I tried plain javascript libraries like jsrsasign but it increases the size of the .wasm file to more than the allowed 256KB for Shopify functions. I'm not able to find any library that I can use within the restrictions. If I implement the hashing my myself, I'm not sure whether I would remain within the instructions count limit.

What are the options for me to get this done sticking to typescript? I'm like kind of stuck on what to do.

Accepted Solution (1)
Nick_Wesselman
Shopify Staff
167 42 65

This is an accepted solution.

What is the instruction count without the message signing?

 

RSA/SHA256 is pretty heavy, what if you just use a SHA-1 HMAC?

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

View solution in original post

Replies 7 (7)

Nick_Wesselman
Shopify Staff
167 42 65

Hi @sriram-1 --

 

Message signing is the only secure way of doing this, and currently there isn't a mechanism for JavaScript/Javy to use crypto in a way that fits within our instruction limits. As mentioned in our docscryptographic hashes, such as SHA implemented in JavaScript, are unlikely to execute within the allowed instruction count.

 

I'd recommend use of Rust for now. We have discussed providing a crypto implementation in Javy. You can upvote the feature request here.

 

-Nick

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

sriram-1
Shopify Partner
6 0 1

@NIc I actually did a Go implementation of this function and compiled it to .wasm using tinygo. I was able to get the file size under 256KB but the instruction count went to 71M. Thus, instruction count limit exceeded in Javascript as well as Go implementations. How sure can I be that this will not be the case if I implement it in Rust? I mean to understand what's special about Rust implementation that can avoid this scenario.

Nick_Wesselman
Shopify Staff
167 42 65

I know of several partners successfully doing crypto operations in Rust.

I'm surprised TinyGo is that high though. What is your instruction count without the message signature verification? What hashing algorithm are you using?

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

Nick_Wesselman
Shopify Staff
167 42 65

You might check the compiler options I'm using here, if you haven't already:

https://github.com/nickwesselman/polyglot-functions/blob/main/app/extensions/order-discount-golang/b...

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

sriram-1
Shopify Partner
6 0 1

The instruction count came close to 72M. And yes, I'm using the same compiler options that you pointed me to. 

 

$ cat input1.json | shopify app function run
      Benchmark Results      

Name: function.wasm
Linear Memory Usage: 512KB
Instructions: 71.539465M
Size: 242KB

 

I'm doing json.Unmarshal and json.Marshal in my main() to handle the input to and output of the function.

And, this is all the crypto operations i'm doing in the Go file. Using RSA, SHA256 

 

       	import (
          "crypto"
	  "crypto/rsa"
	  "crypto/sha256"
	  "crypto/x509"
	  "encoding/base64"
	  "encoding/json"
	  "encoding/pem" 
        )
       //  block, _ := pem.Decode(pemBytes) and  x509.ParsePKCS1PublicKey(block.Bytes)
	pubKey, err := parsePublicKey([]byte(PUBLIC_KEY))

	encodedHeader, encodedPayload, encodedSignature := <derived from token>
	payloadBytes, err := base64.RawURLEncoding.DecodeString(encodedPayload)
	payload := string(payloadBytes)
	signatureBytes, err := base64.RawURLEncoding.DecodeString(encodedSignature)

	data := encodedHeader + "." + encodedPayload
	h := sha256.New()
	h.Write([]byte(data))
	d := h.Sum(nil)
	err = rsa.VerifyPKCS1v15(pubKey, crypto.SHA256, d, signatureBytes)
	if err != nil {
		return "", fmt.Errorf("signature verification failed: %v", err)
	}
	return payload, nil

 

 

Nick_Wesselman
Shopify Staff
167 42 65

This is an accepted solution.

What is the instruction count without the message signing?

 

RSA/SHA256 is pretty heavy, what if you just use a SHA-1 HMAC?

Nick Wesselman | Shopify 
 - Was my reply helpful? Click Like to let me know! 
 - Was your question answered? Mark it as an Accepted Solution
 - To learn more visit the Shopify Help Center or the Shopify Blog

sriram-1
Shopify Partner
6 0 1

Thanks for this suggestion, it worked. The instruction count came down to 1M. The binary size also has come down.