Skip to content

Commit 9b1a4c6

Browse files
committed
feat: relay room authorization for default password
- Default password (pass123) can join existing rooms but cannot create new ones - Track firstAuthorized flag per room - Defer authorization check until both peers connect - At least one peer must know the correct relay password - Auto-cleanup unauthorized rooms after UNAUTHORIZED_ROOM_TTL (1 minute) - Tests: default password join, correct password access, wrong password rejection
1 parent d225c85 commit 9b1a4c6

3 files changed

Lines changed: 117 additions & 21 deletions

File tree

src/tcp/defaults.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ const (
66
DEFAULT_LOG_LEVEL = "debug"
77
DEFAULT_ROOM_CLEANUP_INTERVAL = 10 * time.Minute
88
DEFAULT_ROOM_TTL = 3 * time.Hour
9+
UNAUTHORIZED_ROOM_TTL = time.Minute
910
)

src/tcp/tcp.go

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ type server struct {
3434
}
3535

3636
type roomInfo struct {
37-
first *comm.Comm
38-
second *comm.Comm
39-
opened time.Time
40-
full bool
37+
first *comm.Comm
38+
second *comm.Comm
39+
opened time.Time
40+
full bool
41+
firstAuthorized bool // true if first peer knows the correct relay password
4142
}
4243

4344
type roomMap struct {
@@ -203,6 +204,7 @@ func (s *server) run() (err error) {
203204
break
204205
}
205206
if roomData.first != nil {
207+
deleteIt = !roomData.firstAuthorized && time.Since(roomData.opened) > UNAUTHORIZED_ROOM_TTL
206208
errSend := roomData.first.Send([]byte{1})
207209
if errSend != nil {
208210
log.Debug(errSend)
@@ -325,13 +327,19 @@ func (s *server) clientCommunication(c *comm.Comm) (room string, err error) {
325327
if err != nil {
326328
return
327329
}
328-
if strings.TrimSpace(string(passwordBytes)) != s.password {
330+
clientPassword := strings.TrimSpace(string(passwordBytes))
331+
passwordMatch := clientPassword == s.password
332+
isDefaultPassword := clientPassword == models.DEFAULT_PASSPHRASE
333+
334+
if !passwordMatch && !isDefaultPassword {
335+
// reject if password is neither correct nor default
329336
err = fmt.Errorf("bad password")
330337
enc, _ := crypt.Encrypt([]byte(err.Error()), strongKeyForEncryption)
331338
if err = c.Send(enc); err != nil {
332339
return "", fmt.Errorf("send error: %w", err)
333340
}
334341
return
342+
// default password: authorization checked later
335343
}
336344

337345
// send ok to tell client they are connected
@@ -365,8 +373,9 @@ func (s *server) clientCommunication(c *comm.Comm) (room string, err error) {
365373
// create the room if it is new
366374
if _, ok := s.rooms.rooms[room]; !ok {
367375
s.rooms.rooms[room] = roomInfo{
368-
first: c,
369-
opened: time.Now(),
376+
first: c,
377+
opened: time.Now(),
378+
firstAuthorized: passwordMatch,
370379
}
371380
s.rooms.Unlock()
372381
// tell the client that they got the room
@@ -398,37 +407,52 @@ func (s *server) clientCommunication(c *comm.Comm) (room string, err error) {
398407
return
399408
}
400409
log.Debugf("room %s has 2", room)
410+
firstAuthorized := s.rooms.rooms[room].firstAuthorized
411+
secondAuthorized := passwordMatch
401412
s.rooms.rooms[room] = roomInfo{
402-
first: s.rooms.rooms[room].first,
403-
second: c,
404-
opened: s.rooms.rooms[room].opened,
405-
full: true,
413+
first: s.rooms.rooms[room].first,
414+
second: c,
415+
opened: s.rooms.rooms[room].opened,
416+
full: true,
417+
firstAuthorized: firstAuthorized,
406418
}
407419
otherConnection := s.rooms.rooms[room].first
408420
s.rooms.Unlock()
409421

422+
// check authorization: at least one peer must know the correct relay password
423+
if !firstAuthorized && !secondAuthorized {
424+
log.Debugf("unauthorized: both peers use default password in room %s", room)
425+
err = fmt.Errorf("bad password")
426+
enc, _ := crypt.Encrypt([]byte(err.Error()), strongKeyForEncryption)
427+
c.Send(enc)
428+
s.deleteRoom(room)
429+
return
430+
}
431+
432+
// tell the sender everything is ready
433+
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
434+
if err != nil {
435+
return
436+
}
437+
err = c.Send(bSend)
438+
if err != nil {
439+
s.deleteRoom(room)
440+
return
441+
}
442+
410443
// second connection is the sender, time to staple connections
411444
var wg sync.WaitGroup
412445
wg.Add(1)
413446

414447
// start piping
448+
// after tell the sender everything is ready prevent race sending to sender
415449
go func(com1, com2 *comm.Comm, wg *sync.WaitGroup) {
416450
log.Debug("starting pipes")
417451
pipe(com1.Connection(), com2.Connection())
418452
wg.Done()
419453
log.Debug("done piping")
420454
}(otherConnection, c, &wg)
421455

422-
// tell the sender everything is ready
423-
bSend, err = crypt.Encrypt([]byte("ok"), strongKeyForEncryption)
424-
if err != nil {
425-
return
426-
}
427-
err = c.Send(bSend)
428-
if err != nil {
429-
s.deleteRoom(room)
430-
return
431-
}
432456
wg.Wait()
433457

434458
// delete room

src/tcp/tcp_test.go

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,77 @@ func TestLargeDataTransfer(t *testing.T) {
285285
c2.Close()
286286
}
287287

288+
func TestDefaultPasswordCanJoinExistingRoom(t *testing.T) {
289+
log.SetLevel("error")
290+
go Run("debug", "127.0.0.1", "8395", "secretpass", "8396")
291+
time.Sleep(100 * time.Millisecond)
292+
293+
roomName := "restrictedRoom"
294+
295+
// Sender creates room with correct password
296+
c1, _, _, err := ConnectToTCPServer("127.0.0.1:8395", "secretpass", roomName)
297+
assert.Nil(t, err)
298+
assert.NotNil(t, c1)
299+
300+
// Recipient joins existing room with default password (pass123)
301+
c2, _, _, err := ConnectToTCPServer("127.0.0.1:8395", "pass123", roomName)
302+
assert.Nil(t, err)
303+
assert.NotNil(t, c2)
304+
305+
// Verify data exchange works
306+
assert.Nil(t, c1.Send([]byte("hello from sender")))
307+
var data []byte
308+
for {
309+
data, err = c2.Receive()
310+
if bytes.Equal(data, []byte{1}) {
311+
continue
312+
}
313+
break
314+
}
315+
assert.Nil(t, err)
316+
assert.Equal(t, []byte("hello from sender"), data)
317+
318+
c1.Close()
319+
c2.Close()
320+
}
321+
322+
func TestCorrectPasswordFullAccess(t *testing.T) {
323+
log.SetLevel("error")
324+
go Run("debug", "127.0.0.1", "8399", "secretpass", "8400")
325+
time.Sleep(100 * time.Millisecond)
326+
327+
// Client with correct password can create room
328+
c1, _, _, err := ConnectToTCPServer("127.0.0.1:8399", "secretpass", "fullAccessRoom")
329+
assert.Nil(t, err)
330+
assert.NotNil(t, c1)
331+
332+
// Another client with correct password can join
333+
c2, _, _, err := ConnectToTCPServer("127.0.0.1:8399", "secretpass", "fullAccessRoom")
334+
assert.Nil(t, err)
335+
assert.NotNil(t, c2)
336+
337+
c1.Close()
338+
c2.Close()
339+
}
340+
341+
func TestArbitraryWrongPasswordRejected(t *testing.T) {
342+
log.SetLevel("error")
343+
go Run("debug", "127.0.0.1", "8401", "secretpass", "8402")
344+
time.Sleep(100 * time.Millisecond)
345+
346+
// Sender creates room with correct password
347+
c1, _, _, err := ConnectToTCPServer("127.0.0.1:8401", "secretpass", "arbRoom")
348+
assert.Nil(t, err)
349+
assert.NotNil(t, c1)
350+
351+
// Client with arbitrary wrong password (not default) should be rejected immediately
352+
_, _, _, err = ConnectToTCPServer("127.0.0.1:8401", "somegarbage", "arbRoom")
353+
assert.NotNil(t, err)
354+
assert.Contains(t, err.Error(), "bad password")
355+
356+
c1.Close()
357+
}
358+
288359
func TestServerReleasesPort(t *testing.T) {
289360
log.SetLevel("trace")
290361
host := "127.0.0.1"

0 commit comments

Comments
 (0)