@byoky/relay 0.4.16 → 0.4.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/server.js CHANGED
@@ -5,7 +5,7 @@ const PORT = parseInt(process.env.PORT || "8787", 10);
5
5
  const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
6
6
  const rooms = new Map();
7
7
  const authAttempts = new Map();
8
- const AUTH_RATE_LIMIT = 5;
8
+ const AUTH_RATE_LIMIT = 10;
9
9
  const AUTH_RATE_WINDOW = 60_000;
10
10
  function send(ws, data) {
11
11
  if (ws.readyState === WebSocket.OPEN) {
@@ -48,6 +48,8 @@ wss.on("connection", (ws) => {
48
48
  if (msg.type !== "relay:auth")
49
49
  return;
50
50
  const { roomId, authToken, role } = msg;
51
+ // Clamp priority to 0–1: 0 = fallback (vault), 1 = primary (extension)
52
+ const priority = typeof msg.priority === "number" ? Math.max(0, Math.min(1, Math.floor(msg.priority))) : 1;
51
53
  if (typeof roomId !== "string" ||
52
54
  typeof authToken !== "string" ||
53
55
  (role !== "sender" && role !== "recipient")) {
@@ -55,17 +57,18 @@ wss.on("connection", (ws) => {
55
57
  send(ws, { type: "relay:auth:result", success: false, error: "invalid auth payload" });
56
58
  return;
57
59
  }
58
- console.log(`[auth] attempt: ${role} for room ${roomId.slice(0, 8)}...`);
59
- // Rate limit auth attempts per room
60
+ console.log(`[auth] attempt: ${role} (priority ${priority}) for room ${roomId.slice(0, 8)}...`);
61
+ // Rate limit auth attempts per room+role
60
62
  const now = Date.now();
61
- const attempts = (authAttempts.get(roomId) ?? []).filter((t) => now - t < AUTH_RATE_WINDOW);
63
+ const rateLimitKey = `${roomId}:${role}`;
64
+ const attempts = (authAttempts.get(rateLimitKey) ?? []).filter((t) => now - t < AUTH_RATE_WINDOW);
62
65
  if (attempts.length >= AUTH_RATE_LIMIT) {
63
- console.log(`[auth] rejected: rate limited for room ${roomId.slice(0, 8)}...`);
66
+ console.log(`[auth] rejected: rate limited for ${role} in room ${roomId.slice(0, 8)}...`);
64
67
  send(ws, { type: "relay:auth:result", success: false, error: "too many auth attempts" });
65
68
  return;
66
69
  }
67
70
  attempts.push(now);
68
- authAttempts.set(roomId, attempts);
71
+ authAttempts.set(rateLimitKey, attempts);
69
72
  let room = rooms.get(roomId);
70
73
  if (room) {
71
74
  // Constant-time comparison — pad to equal length so the length
@@ -87,7 +90,7 @@ wss.on("connection", (ws) => {
87
90
  rooms.delete(roomId);
88
91
  console.log(`[auth] deleted stale room ${roomId.slice(0, 8)}... (token mismatch, idle ${Math.round(staleMs / 1000)}s, no active peers)`);
89
92
  // Create fresh room with the new token
90
- room = { authToken, lastActivity: Date.now() };
93
+ room = { authToken, senderPriority: 0, lastActivity: Date.now() };
91
94
  rooms.set(roomId, room);
92
95
  }
93
96
  else {
@@ -97,16 +100,27 @@ wss.on("connection", (ws) => {
97
100
  }
98
101
  }
99
102
  if (room[role] && room[role].readyState === WebSocket.OPEN) {
100
- console.log(`[auth] rejected: ${role} already connected in room ${roomId.slice(0, 8)}...`);
101
- send(ws, { type: "relay:auth:result", success: false, error: `${role} already connected` });
102
- return;
103
+ // Sender priority takeover: higher priority kicks lower priority
104
+ if (role === "sender" && priority > room.senderPriority) {
105
+ console.log(`[auth] takeover: new sender (priority ${priority}) kicks existing (priority ${room.senderPriority}) in room ${roomId.slice(0, 8)}...`);
106
+ send(room.sender, { type: "relay:peer:status", online: false, kicked: true });
107
+ room.sender.close(4001, "replaced by higher-priority sender");
108
+ room.sender = undefined;
109
+ }
110
+ else {
111
+ console.log(`[auth] rejected: ${role} already connected in room ${roomId.slice(0, 8)}...`);
112
+ send(ws, { type: "relay:auth:result", success: false, error: `${role} already connected` });
113
+ return;
114
+ }
103
115
  }
104
116
  }
105
117
  else {
106
- room = { authToken, lastActivity: Date.now() };
118
+ room = { authToken, senderPriority: 0, lastActivity: Date.now() };
107
119
  rooms.set(roomId, room);
108
120
  }
109
121
  room[role] = ws;
122
+ if (role === "sender")
123
+ room.senderPriority = priority;
110
124
  touchRoom(room);
111
125
  authedRoomId = roomId;
112
126
  authedRole = role;
@@ -153,6 +167,8 @@ wss.on("connection", (ws) => {
153
167
  if (!room)
154
168
  return;
155
169
  room[authedRole] = undefined;
170
+ if (authedRole === "sender")
171
+ room.senderPriority = 0;
156
172
  const peer = authedRole === "sender" ? room.recipient : room.sender;
157
173
  if (peer && peer.readyState === WebSocket.OPEN) {
158
174
  send(peer, { type: "relay:peer:status", online: false });
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byoky/relay",
3
- "version": "0.4.16",
3
+ "version": "0.4.18",
4
4
  "description": "WebSocket relay server for Byoky",
5
5
  "type": "module",
6
6
  "main": "dist/server.js",
package/src/server.ts CHANGED
@@ -5,6 +5,7 @@ import { timingSafeEqual } from "node:crypto";
5
5
 
6
6
  interface Room {
7
7
  sender?: WebSocket;
8
+ senderPriority: number;
8
9
  recipient?: WebSocket;
9
10
  authToken: string;
10
11
  lastActivity: number;
@@ -15,7 +16,7 @@ const IDLE_TIMEOUT_MS = 5 * 60 * 1000;
15
16
 
16
17
  const rooms = new Map<string, Room>();
17
18
  const authAttempts = new Map<string, number[]>();
18
- const AUTH_RATE_LIMIT = 5;
19
+ const AUTH_RATE_LIMIT = 10;
19
20
  const AUTH_RATE_WINDOW = 60_000;
20
21
 
21
22
  function send(ws: WebSocket, data: unknown): void {
@@ -64,6 +65,8 @@ wss.on("connection", (ws) => {
64
65
  if (msg.type !== "relay:auth") return;
65
66
 
66
67
  const { roomId, authToken, role } = msg;
68
+ // Clamp priority to 0–1: 0 = fallback (vault), 1 = primary (extension)
69
+ const priority = typeof msg.priority === "number" ? Math.max(0, Math.min(1, Math.floor(msg.priority))) : 1;
67
70
  if (
68
71
  typeof roomId !== "string" ||
69
72
  typeof authToken !== "string" ||
@@ -74,18 +77,19 @@ wss.on("connection", (ws) => {
74
77
  return;
75
78
  }
76
79
 
77
- console.log(`[auth] attempt: ${role} for room ${roomId.slice(0, 8)}...`);
80
+ console.log(`[auth] attempt: ${role} (priority ${priority}) for room ${roomId.slice(0, 8)}...`);
78
81
 
79
- // Rate limit auth attempts per room
82
+ // Rate limit auth attempts per room+role
80
83
  const now = Date.now();
81
- const attempts = (authAttempts.get(roomId) ?? []).filter((t) => now - t < AUTH_RATE_WINDOW);
84
+ const rateLimitKey = `${roomId}:${role}`;
85
+ const attempts = (authAttempts.get(rateLimitKey) ?? []).filter((t) => now - t < AUTH_RATE_WINDOW);
82
86
  if (attempts.length >= AUTH_RATE_LIMIT) {
83
- console.log(`[auth] rejected: rate limited for room ${roomId.slice(0, 8)}...`);
87
+ console.log(`[auth] rejected: rate limited for ${role} in room ${roomId.slice(0, 8)}...`);
84
88
  send(ws, { type: "relay:auth:result", success: false, error: "too many auth attempts" });
85
89
  return;
86
90
  }
87
91
  attempts.push(now);
88
- authAttempts.set(roomId, attempts);
92
+ authAttempts.set(rateLimitKey, attempts);
89
93
 
90
94
  let room = rooms.get(roomId);
91
95
 
@@ -109,7 +113,7 @@ wss.on("connection", (ws) => {
109
113
  rooms.delete(roomId);
110
114
  console.log(`[auth] deleted stale room ${roomId.slice(0, 8)}... (token mismatch, idle ${Math.round(staleMs / 1000)}s, no active peers)`);
111
115
  // Create fresh room with the new token
112
- room = { authToken, lastActivity: Date.now() };
116
+ room = { authToken, senderPriority: 0, lastActivity: Date.now() };
113
117
  rooms.set(roomId, room);
114
118
  } else {
115
119
  console.log(`[auth] rejected: token mismatch for room ${roomId.slice(0, 8)}...`);
@@ -118,16 +122,25 @@ wss.on("connection", (ws) => {
118
122
  }
119
123
  }
120
124
  if (room[role] && room[role]!.readyState === WebSocket.OPEN) {
121
- console.log(`[auth] rejected: ${role} already connected in room ${roomId.slice(0, 8)}...`);
122
- send(ws, { type: "relay:auth:result", success: false, error: `${role} already connected` });
123
- return;
125
+ // Sender priority takeover: higher priority kicks lower priority
126
+ if (role === "sender" && priority > room.senderPriority) {
127
+ console.log(`[auth] takeover: new sender (priority ${priority}) kicks existing (priority ${room.senderPriority}) in room ${roomId.slice(0, 8)}...`);
128
+ send(room.sender!, { type: "relay:peer:status", online: false, kicked: true });
129
+ room.sender!.close(4001, "replaced by higher-priority sender");
130
+ room.sender = undefined;
131
+ } else {
132
+ console.log(`[auth] rejected: ${role} already connected in room ${roomId.slice(0, 8)}...`);
133
+ send(ws, { type: "relay:auth:result", success: false, error: `${role} already connected` });
134
+ return;
135
+ }
124
136
  }
125
137
  } else {
126
- room = { authToken, lastActivity: Date.now() };
138
+ room = { authToken, senderPriority: 0, lastActivity: Date.now() };
127
139
  rooms.set(roomId, room);
128
140
  }
129
141
 
130
142
  room[role] = ws;
143
+ if (role === "sender") room.senderPriority = priority;
131
144
  touchRoom(room);
132
145
  authedRoomId = roomId;
133
146
  authedRole = role;
@@ -185,6 +198,7 @@ wss.on("connection", (ws) => {
185
198
  if (!room) return;
186
199
 
187
200
  room[authedRole] = undefined;
201
+ if (authedRole === "sender") room.senderPriority = 0;
188
202
 
189
203
  const peer = authedRole === "sender" ? room.recipient : room.sender;
190
204
  if (peer && peer.readyState === WebSocket.OPEN) {