Skip to content

Commit 729af71

Browse files
Implement initial bindings
0 parents  commit 729af71

File tree

12 files changed

+737
-0
lines changed

12 files changed

+737
-0
lines changed

.github/workflows/ci.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: CI
2+
3+
# Run CI when a PR is opened against the branch `master`
4+
# and when one pushes a commit to `master`.
5+
on:
6+
push:
7+
branches: [master]
8+
pull_request:
9+
branches: [master]
10+
11+
# Run CI on all 3 latest OSes
12+
jobs:
13+
build:
14+
strategy:
15+
matrix:
16+
os: [ubuntu-latest, macos-latest, windows-latest]
17+
runs-on: ${{ matrix.os }}
18+
19+
steps:
20+
- uses: actions/checkout@v3
21+
22+
- name: Set up Node toolchain
23+
uses: actions/setup-node@v3
24+
with:
25+
node-version: "18"
26+
27+
- name: Cache NPM dependencies
28+
uses: actions/cache@v3
29+
env:
30+
cache-name: cache-node-modules
31+
with:
32+
path: ~/.npm
33+
key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package.json') }}
34+
restore-keys: |
35+
${{ runner.os }}-build-${{ env.cache-name }}-
36+
${{ runner.os }}-build-
37+
${{ runner.os }}-
38+
39+
- name: Setup PureScript tooling
40+
run:
41+
npm i -g purescript@latest purs-tidy@latest purescript-psa@latest spago@latest
42+
43+
- name: Cache PureScript dependencies
44+
uses: actions/cache@v3
45+
with:
46+
key: ${{ runner.os }}-spago-${{ hashFiles('**/*.dhall') }}
47+
path: |
48+
.spago
49+
output
50+
51+
# Compile the library/project
52+
# censor-lib: ignore warnings emitted by dependencies
53+
# strict: convert warnings into errors
54+
# Note: `purs-args` actually forwards these args to `psa`
55+
- name: Build the project
56+
run: |
57+
npx spago build --purs-args "--censor-lib --strict"
58+
59+
- name: Check Formatting
60+
if: runner.os == 'Linux'
61+
run: |
62+
purs-tidy check src test

.gitignore

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/bower_components/
2+
/node_modules/
3+
/.pulp-cache/
4+
/output/
5+
/generated-docs/
6+
/.psc-package/
7+
/.psc*
8+
/.purs*
9+
/.psa*
10+
/.spago

packages.dhall

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
let upstream =
2+
https://github.com/purescript/package-sets/releases/download/psc-0.15.8-20230615/packages.dhall
3+
sha256:96d5db51eb6ce51906b52377d615fcdca3528ac05e0dc58e71ace8bbaceac108
4+
5+
in upstream
6+
with node-event-emitter.version = "v2.0.0"
7+
with node-event-emitter.dependencies =
8+
[ "effect"
9+
, "either"
10+
, "functions"
11+
, "prelude"
12+
, "unsafe-coerce"
13+
]
14+
with node-streams.version = "eb31fe5d4040d5da4b4143c9f33d11a3ab1a9bdd"
15+
with node-streams.dependencies =
16+
[ "effect"
17+
, "exceptions"
18+
, "maybe"
19+
, "node-buffer"
20+
, "node-event-emitter"
21+
, "nullable"
22+
, "prelude"
23+
, "unsafe-coerce"
24+
]
25+
with node-net.version = "4d408a3b5f1025f56f5c1e97cb6f833a8f04651b"
26+
with node-net.dependencies =
27+
[ "console"
28+
, "datetime"
29+
, "effect"
30+
, "exceptions"
31+
, "maybe"
32+
, "node-buffer"
33+
, "node-event-emitter"
34+
, "node-fs"
35+
, "node-streams"
36+
, "nullable"
37+
, "partial"
38+
, "prelude"
39+
, "unsafe-coerce"
40+
]

spago.dhall

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
{ name = "my-project"
2+
, dependencies =
3+
[ "console"
4+
, "effect"
5+
, "either"
6+
, "exceptions"
7+
, "foreign"
8+
, "maybe"
9+
, "node-buffer"
10+
, "node-event-emitter"
11+
, "node-net"
12+
, "node-streams"
13+
, "nullable"
14+
, "partial"
15+
, "prelude"
16+
, "unsafe-coerce"
17+
]
18+
, packages = ./packages.dhall
19+
, sources = [ "src/**/*.purs" ]
20+
, license = "MIT"
21+
}

src/Main.purs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
module Main where
2+
3+
import Prelude
4+
5+
import Effect (Effect)
6+
import Effect.Console (log)
7+
8+
main :: Effect Unit
9+
main = do
10+
log "🍝"

src/Node/TLS.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import tls from "node:tls";
2+
export {
3+
rootCertificates,
4+
DEFAULT_ECDH_CURVE as defaultEcdhCurve,
5+
DEFAULT_MAX_VERSION as defaultMinVersion,
6+
DEFAULT_MIN_VERSION as defaultMaxVersion,
7+
DEFAULT_CIPHERS as defaultCiphers,
8+
} from "node:tls";
9+
10+
export const checkServerIdentityImpl = (hostname, cert) => tls.checkServerIdentity(hostname, cert);
11+
export const createSecureContext = () => tls.createSecureContext();
12+
export const createSecureContextOptionsImpl = (o) => tls.createSecureContext(o);
13+
export const getCiphers = () => tls.getCiphers();
14+

src/Node/TLS.purs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
module Node.TLS
2+
( checkServerIdentity
3+
, createSecureContext
4+
, createSecureContext'
5+
, getCiphers
6+
, rootCertificates
7+
, defaultEcdhCurve
8+
, defaultMinVersion
9+
, defaultMaxVersion
10+
) where
11+
12+
import Prelude
13+
14+
import Data.Maybe (Maybe)
15+
import Data.Nullable (Nullable, toMaybe)
16+
import Effect (Effect)
17+
import Effect.Exception (Error)
18+
import Effect.Uncurried (EffectFn1, EffectFn2, runEffectFn1, runEffectFn2)
19+
import Foreign (Foreign)
20+
import Node.TLS.Types (CreateSecureContextOptions, SecureContext)
21+
import Prim.Row as Row
22+
23+
checkServerIdentity :: String -> Foreign -> Effect (Maybe Error)
24+
checkServerIdentity hostname cert = map toMaybe $ runEffectFn2 checkServerIdentityImpl hostname cert
25+
26+
foreign import checkServerIdentityImpl :: EffectFn2 (String) (Foreign) (Nullable Error)
27+
28+
foreign import createSecureContext :: Effect (SecureContext)
29+
30+
createSecureContext'
31+
:: forall r trash
32+
. Row.Union r trash (CreateSecureContextOptions ())
33+
=> { | r }
34+
-> Effect SecureContext
35+
createSecureContext' o = runEffectFn1 createSecureContextOptionsImpl o
36+
37+
foreign import createSecureContextOptionsImpl :: forall r. EffectFn1 ({ | r }) (SecureContext)
38+
39+
foreign import getCiphers :: Effect (Array String)
40+
41+
foreign import rootCertificates :: Array String
42+
43+
foreign import defaultEcdhCurve :: String
44+
foreign import defaultMinVersion :: String
45+
foreign import defaultMaxVersion :: String
46+
foreign import defaultCiphers :: String

src/Node/TLS/Server.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import tls from "node:tls";
2+
3+
export const createServer = () => tls.createServer();
4+
export const createServerOptionsImpl = (o) => tls.createServer(o);
5+
export const addContextImpl = (s, hostname, context) => s.addContext(hostname, context);
6+
export const getTicketKeysImpl = (s) => s.getTicketKeys();
7+
export const setSecureContextImpl = (s, o) => s.setSecureContext(o);
8+
export const setTicketKeysImpl = (s, b) => s.setTicketKeys(b);

src/Node/TLS/Server.purs

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
module Node.TLS.Server
2+
( toNetServer
3+
, createServer
4+
, createServer'
5+
, keylogHandle
6+
, newSessionHandle
7+
, ocspRequestHandle
8+
, resumeSessionHandle
9+
, secureConnectionHandle
10+
, tlsClientErrorHandle
11+
, addContext
12+
, getTicketKeys
13+
, setSecureContext
14+
, setTicketKeys
15+
) where
16+
17+
import Prelude
18+
19+
import Data.Either (Either(..))
20+
import Data.Maybe (Maybe(..))
21+
import Data.Nullable (Nullable, notNull, null)
22+
import Effect (Effect)
23+
import Effect.Exception (Error)
24+
import Effect.Uncurried (EffectFn1, EffectFn2, EffectFn3, mkEffectFn1, mkEffectFn2, mkEffectFn3, runEffectFn1, runEffectFn2, runEffectFn3)
25+
import Node.Buffer (Buffer)
26+
import Node.EventEmitter (EventHandle(..))
27+
import Node.EventEmitter.UtilTypes (EventHandle2, EventHandle3, EventHandle1)
28+
import Node.Net.Types as NetTypes
29+
import Node.TLS.Types (CreateSecureContextOptions, Server, TlsCreateServerOptions, TlsServer, TlsSocket)
30+
import Prim.Row as Row
31+
import Unsafe.Coerce (unsafeCoerce)
32+
33+
toNetServer :: TlsServer -> NetTypes.Server NetTypes.TCP
34+
toNetServer = unsafeCoerce
35+
36+
foreign import createServer :: Effect (TlsServer)
37+
38+
createServer'
39+
:: forall r trash
40+
. Row.Union r trash (TlsCreateServerOptions Server (CreateSecureContextOptions (NetTypes.NewServerOptions ())))
41+
=> { | r }
42+
-> Effect (TlsServer)
43+
createServer' r = runEffectFn1 createServerOptionsImpl r
44+
45+
foreign import createServerOptionsImpl :: forall r. EffectFn1 { | r } (TlsServer)
46+
47+
keylogHandle :: forall endpoint. EventHandle2 TlsServer Buffer (TlsSocket endpoint)
48+
keylogHandle = EventHandle "keylog" \cb -> mkEffectFn2 \a b -> cb a b
49+
50+
newSessionHandle :: EventHandle3 TlsServer Buffer Buffer (Effect Unit)
51+
newSessionHandle = EventHandle "newSession" \cb -> mkEffectFn3 \a b c -> cb a b c
52+
53+
ocspRequestHandle
54+
:: EventHandle
55+
TlsServer
56+
(Buffer -> (Maybe (Either Error Buffer) -> Effect Unit) -> Effect Unit)
57+
(EffectFn2 Buffer (EffectFn2 (Nullable Error) (Nullable Buffer) Unit) Unit)
58+
ocspRequestHandle = EventHandle "ocspRequest" \cb ->
59+
mkEffectFn2 \buff cb' ->
60+
cb buff $ case _ of
61+
Nothing -> runEffectFn2 cb' null null
62+
Just x -> case x of
63+
Left err -> runEffectFn2 cb' (notNull err) null
64+
Right buff' -> runEffectFn2 cb' null (notNull buff')
65+
66+
resumeSessionHandle
67+
:: EventHandle
68+
TlsServer
69+
(Buffer -> (Either Error Buffer -> Effect Unit) -> Effect Unit)
70+
(EffectFn2 Buffer (EffectFn2 (Nullable Error) (Nullable Buffer) Unit) Unit)
71+
resumeSessionHandle = EventHandle "resumeSession" \cb ->
72+
mkEffectFn2 \buff cb' ->
73+
cb buff $ case _ of
74+
Left err -> runEffectFn2 cb' (notNull err) null
75+
Right buff' -> runEffectFn2 cb' null (notNull buff')
76+
77+
secureConnectionHandle :: forall endpoint. EventHandle1 TlsServer (TlsSocket endpoint)
78+
secureConnectionHandle = EventHandle "secureConnection" mkEffectFn1
79+
80+
tlsClientErrorHandle :: forall endpoint. EventHandle2 TlsServer Error (TlsSocket endpoint)
81+
tlsClientErrorHandle = EventHandle "tlsClientError" \cb -> mkEffectFn2 \a b -> cb a b
82+
83+
addContext
84+
:: forall r trash
85+
. Row.Union r trash (CreateSecureContextOptions ())
86+
=> TlsServer
87+
-> String
88+
-> { | r }
89+
-> Effect Unit
90+
addContext s hostname o = runEffectFn3 addContextImpl s hostname o
91+
92+
foreign import addContextImpl :: forall r. EffectFn3 (TlsServer) (String) ({ | r }) (Unit)
93+
94+
getTicketKeys :: TlsServer -> Effect Buffer
95+
getTicketKeys s = runEffectFn1 getTicketKeysImpl s
96+
97+
foreign import getTicketKeysImpl :: EffectFn1 (TlsServer) (Buffer)
98+
99+
setSecureContext
100+
:: forall r trash
101+
. Row.Union r trash (CreateSecureContextOptions ())
102+
=> TlsServer
103+
-> { | r }
104+
-> Effect Unit
105+
setSecureContext s o = runEffectFn2 setSecureContextImpl s o
106+
107+
foreign import setSecureContextImpl :: forall r. EffectFn2 (TlsServer) ({ | r }) (Unit)
108+
109+
setTicketKeys :: TlsServer -> Buffer -> Effect Unit
110+
setTicketKeys t b = runEffectFn2 setTicketKeysImpl t b
111+
112+
foreign import setTicketKeysImpl :: EffectFn2 (TlsServer) (Buffer) (Unit)

src/Node/TLS/Socket.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import tls from "node:tls";
2+
3+
export const newTlsSocketImpl = (s) => new tls.TLSSocket(s);
4+
export const newTlsSocketOptionsImpl = (s, o) => new tls.TLSSocket(s, o);
5+
export const connectImpl = (o) => tls.connect(o);
6+
export const authorizationErrorImpl = (s) => s.authorizationError;
7+
export const authorizedImpl = (s) => s.authorized;
8+
// export const disableRenegotiationImpl = (s) => s.disableRenegotiation();
9+
export const enableTraceImpl = (s) => s.enableTrace();
10+
export const encryptedImpl = (s) => s.encrypted;
11+
export const exportKeyingMaterialImpl = (s, len, label) => s.exportKeyingMaterial(len, label);
12+
export const exportKeyingMaterialOptionsImpl = (s, len, label, context) => s.exportKeyingMaterial(len, label, context);
13+
export const getCertificateImpl = (s) => s.getCertificate();
14+
export const getCipherImpl = (s) => s.getCipher();
15+
export const getEphemeralKeyInfoImpl = (s) => s.getEphemeralKeyInfo();
16+
export const getFinishedImpl = (s) => s.getFinished();
17+
export const getPeerCertificateImpl = (s) => s.getPeerCertificate();
18+
export const getPeerCertificateOptionsImpl = (s, o) => s.getPeerCertificate(o);
19+
export const getPeerFinishedImpl = (s) => s.getPeerFinished();
20+
export const getPeerX509CertificateImpl = (s) => s.getPeerX509Certificate();
21+
export const getProtocolImpl = (s) => s.getProtocol();
22+
export const getSessionImpl = (s) => s.getSession();
23+
export const getSharedSigalgsImpl = (s) => s.getSharedSigalgs();
24+
export const getTLSTicketImpl = (s) => s.getTLSTicket();
25+
export const getX509CertificateImpl = (s) => s.getX509Certificate();
26+
export const isSessionReusedImpl = (s) => s.isSessionReused();
27+
export const setMaxSendFragmentImpl = (s, size) => s.setMaxSendFragment(size);

0 commit comments

Comments
 (0)