I have a Go server and client using a local trusted certificate and they communicate flawless with each other. Now I want the Go server to communicate with a web-grpc instance too. Insecure didn't work as browsers force HTTP2 to go over TLS or deny it fully. And after all; it should work on TLS in production too anyway. Another issue is CORS too, which I can't figure out yet to give to https://github.com/improbable-eng/grpc-web 's version of the server implementation to add origin headers. But first things first.
I serve a simple HTML and Webpack build JS that I serve with a simple Golang FileServer over TLS.
I first generated a new TLS cert/key (that the already-working Go Server/Client pair use successfully):
openssl req -new -newkey rsa:4096 -days 365 -nodes -x509 -subj "/C=US/ST=State/L=Town/O=Office/CN=www.wp-ts.loc" -keyout ./www.wp-ts.loc.key -out ./www.wp-ts.loc
Then I added it to the macOS keychain to be trusted:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain www.wp-ts.loc
This is the Protobuf file I use:
syntax = "proto3";
package pb;
service GCDService {
rpc Compute (GCDRequest) returns (GCDResponse) {}
}
message GCDRequest {
uint64 a = 1;
uint64 b = 2;
}
message GCDResponse {
uint64 result = 1;
}
Then build with:
protoc -I=. gcd.proto \
--js_out=import_style=commonjs:. \
--grpc-web_out=import_style=commonjs,mode=grpcwebtext:.
This is the simple HTML page I serve:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>gRPC</title>
<script src=".//dist/main.js"></script>
</head>
<body>
</body>
</html>
Then the JS module:
import { grpc } from "grpc";
import { GCDRequest, GCDResponse } from "./gcd_pb.js";
import { GCDServiceClient } from "./gcd_grpc_web_pb.js";
var root_certs = ["www.wp-ts.loc", "www.wp-ts.loc.key"];
var sslCredentials = grpc.credentials.createSsl(...root_certs);
var client = new GCDServiceClient("https://www.wp-ts.loc:3000", sslCredentials);
var request = new GCDRequest();
request.setA(294);
request.setB(462);
client.compute(request, {}, (err, response) => {
console.log(err);
console.log(response);
// console.log(response.getResult());
});
Which is build with Webpack like so (which outputs to ./dist/main.js
and thus read by the index.html
):
npx webpack client.js
The www.wp-ts.loc
test domain is in my /etc/host
so it can mimic as a domain with the certificate and reroute all traffic to localhost.
Now here's the issue I can't really seem to find in all the big library overhead as this mainly seems to be meant for NodeJS. The Webpack builder with new GCDServiceClient()
without credentials builds fine, but of course the browser won't allow the non-TLS style (leaving CORS out of the equation for now). Then using the credentials as a test (which of course is dangerous, but I'm trying out along the way and can't find good docs for it on grpc-web style) gives the obvious NodeJS issue that it can't use the filesystem:
... // Many lines here, but this is clear enough I guess
ERROR in ./node_modules/grpc/src/grpc_extension.js
Module not found: Error: Can't resolve 'fs' in '/Users/#USERNAME/Downloads/wp-ts/node_modules/grpc/src'
@ ./node_modules/grpc/src/grpc_extension.js 34:11-24
@ ./node_modules/grpc/index.js
@ ./client.js
Maybe I'm just approaching this totally wrong and I'm also aware that the grpc-web
implementation is still in a very brittle phase, but how do you make it work to connect correctly over HTTP2/TLS (with certificate) and maybe if known to get the CORS headers to be added to https://github.com/improbable-eng/grpc-web 's server that I add to my Listener in Go at port 3000.
Sorry for big gist, but I hope someone can help me with this. I'm really excited to get going with Go + Browser gRPC/Protobuf :D
Thank you so much in advance!