Skip to content

Instantly share code, notes, and snippets.

@duanebester
Created June 3, 2022 17:58
Show Gist options
  • Save duanebester/0e40bee407072a213bf26ae264edb538 to your computer and use it in GitHub Desktop.
Save duanebester/0e40bee407072a213bf26ae264edb538 to your computer and use it in GitHub Desktop.
Talk to Postgres w/ Unison
use .base
-- SQL password message: concat('md5', md5(concat(md5(concat(password, username)), random-salt)))
-- "md58393de45eea6f814e37f41f02540710c"
calculatePassword: Text -> Text -> Bytes -> Text
calculatePassword username password salt =
use md5 md5EncodeAscii md5Encode
userpassMd5 = md5EncodeAscii (password ++ username)
use Text toUtf8
userpassMd5Bytes = (toUtf8 userpassMd5)
combinedMd5Bytes = md5Encode (userpassMd5Bytes ++ salt)
use md5.utils bytesToHexText
hexText = bytesToHexText combinedMd5Bytes
pw = "md5" ++ hexText
pw
buildStartupMessage: Text -> Text -> Bytes
buildStartupMessage username database =
use Text size
use Bytes encodeNat32be
len = (encodeNat32be ((size username) + (size database) + 16 + 4 + 4 + 1))
startup = (encodeNat32be 196608)
use Text toUtf8
u1 = (toUtf8 "user\0")
u2 = (toUtf8 (username ++ "\0"))
d1 = (toUtf8 "database\0")
d2 = (toUtf8 (database ++ "\0"))
use Bytes fromList
b = (fromList [0])
bs = (len ++ startup ++ u1 ++ u2 ++ d1 ++ d2 ++ b)
bs
buildPasswordMessage: Text -> Bytes
buildPasswordMessage password =
use Text size
use Bytes encodeNat32be
len = (encodeNat32be ((size password) + 4 + 1))
use Bytes fromList
pwTag = (fromList [112])
data = (Text.toUtf8 (password ++ "\0"))
bs = (pwTag ++ len ++ data)
bs
unique type BackendMessage
= { tag: Nat,
length: Nat,
data: Bytes }
recvMessage: Socket ->{Exception, IO} BackendMessage
recvMessage socket =
tagByte = io.socketReceive socket 1
tag = (Optional.getOrElse 0 (Bytes.at 0 tagByte))
lenBytes = io.socketReceive socket 4
lenMaybe = (Bytes.decodeNat32be lenBytes)
len = match lenMaybe with
None -> 0
Some (x, y) -> x
use Nat drop
remaining = drop len 4
remBytes = io.socketReceive socket remaining
BackendMessage tag len remBytes
host = HostName "localhost"
port = ServiceName "5432"
program : '{IO, Exception} ()
program = 'let
socket = io.clientSocket host port
printLine "Sending Startup Message"
socketSend socket (buildStartupMessage "jimmy" "world")
recv = recvMessage socket
use Text ++
use Text join
use Nat toText
printLine "Receiving Message"
printLine ("Tag: " ++ (toText (BackendMessage.tag recv)))
printLine ("Length: " ++ (toText (BackendMessage.length recv)))
printLine ("Data: " ++ (join ", " (List.map (elem -> (toText elem)) (Bytes.toList (BackendMessage.data recv)))))
pw = calculatePassword "jimmy" "banana" (Bytes.drop 4 (BackendMessage.data recv))
printLine "Sending Password Message"
socketSend socket (buildPasswordMessage pw)
recv2 = recvMessage socket
printLine "Receiving Message"
printLine ("Tag: " ++ (toText (BackendMessage.tag recv2)))
printLine ("Length: " ++ (toText (BackendMessage.length recv2)))
printLine ("Data: " ++ (join ", " (List.map (elem -> (toText elem)) (Bytes.toList (BackendMessage.data recv2)))))
base.io.closeSocket socket
@duanebester
Copy link
Author

Docker Compose file for reference:

version: '3.9'
services:
  postgres:
    image: postgres:13
    ports:
      - 5432:5432
    environment:
      POSTGRES_USER: jimmy
      POSTGRES_PASSWORD: banana
      POSTGRES_DB: world
    # POSTGRES_HOST_AUTH_METHOD: trust
    volumes:
      - ./.data/world.sql:/docker-entrypoint-initdb.d/world.sql

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment