2025-02-21 10:13:41 -05:00
import db from "@server/db" ;
import { MessageHandler } from "../ws" ;
2025-03-15 21:45:53 -04:00
import { clients , exitNodes , Olm , olms , sites } from "@server/db/schema" ;
2025-03-14 09:18:13 -04:00
import { eq } from "drizzle-orm" ;
2025-02-21 10:55:38 -05:00
import { addPeer , deletePeer } from "../newt/peers" ;
2025-02-21 10:13:41 -05:00
import logger from "@server/logger" ;
export const handleOlmRegisterMessage : MessageHandler = async ( context ) = > {
2025-02-21 12:17:56 -05:00
const { message , client : c , sendToClient } = context ;
const olm = c as Olm ;
2025-02-21 10:13:41 -05:00
2025-02-21 10:55:38 -05:00
logger . info ( "Handling register olm message!" ) ;
2025-02-21 10:13:41 -05:00
if ( ! olm ) {
logger . warn ( "Olm not found" ) ;
return ;
}
2025-02-21 12:17:56 -05:00
if ( ! olm . clientId ) {
2025-02-21 10:13:41 -05:00
logger . warn ( "Olm has no site!" ) ; // TODO: Maybe we create the site here?
return ;
}
2025-02-21 12:17:56 -05:00
const clientId = olm . clientId ;
2025-02-21 10:13:41 -05:00
const { publicKey } = message . data ;
if ( ! publicKey ) {
logger . warn ( "Public key not provided" ) ;
return ;
}
2025-02-21 12:17:56 -05:00
const [ client ] = await db
. select ( )
. from ( clients )
. where ( eq ( clients . clientId , clientId ) )
. limit ( 1 ) ;
if ( ! client || ! client . siteId ) {
logger . warn ( "Site not found or does not have exit node" ) ;
return ;
}
2025-02-21 10:13:41 -05:00
const [ site ] = await db
. select ( )
. from ( sites )
2025-02-21 12:17:56 -05:00
. where ( eq ( sites . siteId , client . siteId ) )
2025-02-21 10:13:41 -05:00
. limit ( 1 ) ;
2025-03-15 21:45:53 -04:00
if ( ! site ) {
2025-02-21 10:13:41 -05:00
logger . warn ( "Site not found or does not have exit node" ) ;
return ;
}
2025-03-15 21:45:53 -04:00
if ( ! site . exitNodeId ) {
logger . warn ( "Site does not have exit node" ) ;
2025-02-22 11:20:56 -05:00
return ;
}
2025-03-15 21:45:53 -04:00
const [ exitNode ] = await db
. select ( )
. from ( exitNodes )
. where ( eq ( exitNodes . exitNodeId , site . exitNodeId ) )
. limit ( 1 ) ;
2025-03-14 09:18:13 -04:00
sendToClient ( olm . olmId , {
type : "olm/wg/holepunch" ,
data : {
2025-03-15 21:45:53 -04:00
serverPubKey : exitNode.publicKey ,
2025-03-14 09:18:13 -04:00
}
} ) ;
2025-03-15 21:45:53 -04:00
// make sure we hand endpoints for both the site and the client and the lastHolePunch is not too old
if ( ! site . endpoint || ! client . endpoint ) {
logger . warn ( "Site or client has no endpoint or listen port" ) ;
return ;
}
2025-02-22 11:20:56 -05:00
const now = new Date ( ) . getTime ( ) / 1000 ;
if ( site . lastHolePunch && now - site . lastHolePunch > 6 ) {
logger . warn ( "Site last hole punch is too old" ) ;
return ;
}
if ( client . lastHolePunch && now - client . lastHolePunch > 6 ) {
logger . warn ( "Client last hole punch is too old" ) ;
return ;
}
2025-02-21 10:13:41 -05:00
await db
2025-02-21 12:17:56 -05:00
. update ( clients )
2025-02-21 10:13:41 -05:00
. set ( {
pubKey : publicKey
} )
2025-02-21 12:17:56 -05:00
. where ( eq ( clients . clientId , olm . clientId ) )
2025-02-21 10:13:41 -05:00
. returning ( ) ;
2025-02-21 12:17:56 -05:00
if ( client . pubKey && client . pubKey !== publicKey ) {
2025-02-21 10:13:41 -05:00
logger . info ( "Public key mismatch. Deleting old peer..." ) ;
2025-02-21 12:17:56 -05:00
await deletePeer ( site . siteId , client . pubKey ) ;
2025-02-21 10:13:41 -05:00
}
if ( ! site . subnet ) {
logger . warn ( "Site has no subnet" ) ;
return ;
}
2025-03-14 09:18:13 -04:00
2025-02-21 10:13:41 -05:00
// add the peer to the exit node
2025-02-21 10:55:38 -05:00
await addPeer ( site . siteId , {
2025-02-21 10:13:41 -05:00
publicKey : publicKey ,
2025-02-22 11:20:56 -05:00
allowedIps : [ client . subnet ] ,
endpoint : client.endpoint
2025-02-21 10:13:41 -05:00
} ) ;
return {
message : {
type : "olm/wg/connect" ,
data : {
2025-02-22 11:20:56 -05:00
endpoint : site.endpoint ,
2025-02-21 10:55:38 -05:00
publicKey : site.publicKey ,
serverIP : site.address ! . split ( "/" ) [ 0 ] ,
2025-03-14 09:18:13 -04:00
tunnelIP : ` ${ client . subnet . split ( "/" ) [ 0 ] } / ${ site . address ! . split ( "/" ) [ 1 ] } ` // put the client ip in the same subnet as the site. TODO: Is this right? Maybe we need th make .subnet work properly!
2025-02-21 10:13:41 -05:00
}
} ,
broadcast : false , // Send to all olms
excludeSender : false // Include sender in broadcast
} ;
} ;