diff --git a/Peercord Source/package.json b/Peercord Source/package.json index 2a0fb39..38da9f5 100644 --- a/Peercord Source/package.json +++ b/Peercord Source/package.json @@ -1,6 +1,6 @@ { "name": "peercord", - "version": "1.0.2", + "version": "1.0.3", "description": "Peercord, A P2P Discord clone powered by Pear Runtime", "author": "Mastercodeon", "main": "index.js", diff --git a/Peercord Source/public/version.js b/Peercord Source/public/version.js index 52ec0c0..0d9403e 100644 --- a/Peercord Source/public/version.js +++ b/Peercord Source/public/version.js @@ -1,2 +1,2 @@ -window.APP_VERSION = '1.0.2'; -window.APP_VERSION_COLOR = 'hsl(119, 80%, 60%)'; +window.APP_VERSION = '1.0.3'; +window.APP_VERSION_COLOR = 'hsl(120, 80%, 60%)'; diff --git a/Peercord Source/src/components/MainApp.jsx b/Peercord Source/src/components/MainApp.jsx index 58220e6..f248955 100644 --- a/Peercord Source/src/components/MainApp.jsx +++ b/Peercord Source/src/components/MainApp.jsx @@ -704,7 +704,7 @@ export default function MainApp({ profile, setProfile, onLogout, updateState, si
{/* Chat Area (Hidden if CallView is active) */} -
+
{activeView === 'dms' && activeDm === 'friends' ? ( ) : ( @@ -741,7 +741,7 @@ export default function MainApp({ profile, setProfile, onLogout, updateState, si {/* 1-on-1 Call View */} {activeCall && ( data.status === 'pending_outgoing') + .map(([key]) => key); + + const identityMsg = JSON.stringify({ + type: 'identity', + displayName: this.displayName, + username: this.username, + avatar: this.avatar, + bio: this.bio, + connections: this.connections, + coreKey: this.coreKey, + topics: Array.from(this.joinedTopics), + pendingTargets + }); + + const payload = b4a.from(identityMsg); + for (const { conn } of this.peers.values()) { + try { conn.write(payload); } catch(e) {} + } + } + async initialize(seedHex, displayName, username, avatar = null, bio = '', connections = []) { this.displayName = displayName; this.username = (username || 'unknown').toLowerCase(); @@ -398,7 +423,23 @@ class P2PNetwork { this.store.replicate(conn); const peerKey = b4a.toString(info.publicKey, 'hex'); this.peers.set(peerKey, { conn, displayName: 'Unknown', username: 'unknown', avatar: null, bio: '', connections: [], coreKey: null }); - const identityMsg = JSON.stringify({ type: 'identity', displayName: this.displayName, username: this.username, avatar: this.avatar, bio: this.bio, connections: this.connections, coreKey: this.coreKey }); + + const pendingTargets = Object.entries(this.dms) + .filter(([_, data]) => data.status === 'pending_outgoing') + .map(([key]) => key); + + const identityMsg = JSON.stringify({ + type: 'identity', + displayName: this.displayName, + username: this.username, + avatar: this.avatar, + bio: this.bio, + connections: this.connections, + coreKey: this.coreKey, + topics: Array.from(this.joinedTopics), + pendingTargets + }); + conn.write(b4a.from(identityMsg)); if (this.onPeerUpdate) this.onPeerUpdate(this.getPeerList()); conn.on('data', async (data) => handleData(this, peerKey, data, conn)); @@ -477,6 +518,9 @@ class P2PNetwork { this.joinedTopics.add(topicHex); const topic = b4a.from(topicHex, 'hex'); this.swarm.join(topic, { client: true, server: true }); + + this._broadcastIdentity(); + if (!skipFlush) { try { await this.swarm.flush(); } catch(e) {} } diff --git a/Peercord Source/src/p2p/modules/identity.js b/Peercord Source/src/p2p/modules/identity.js index a640ce7..7474936 100644 --- a/Peercord Source/src/p2p/modules/identity.js +++ b/Peercord Source/src/p2p/modules/identity.js @@ -59,9 +59,5 @@ export function updateProfile(network, displayName, avatar, username, bio = '', network._emitKnownProfiles(); if (!network.swarm) return; - - const identityMsg = JSON.stringify({ type: 'identity', displayName: network.displayName, username: network.username, avatar: network.avatar, bio: network.bio, connections: network.connections, coreKey: network.coreKey }); - const payload = b4a.from(identityMsg); - for (const { conn } of network.peers.values()) conn.write(payload); - network._emitMessages(); + network._broadcastIdentity(); } \ No newline at end of file diff --git a/Peercord Source/src/p2p/modules/messaging.js b/Peercord Source/src/p2p/modules/messaging.js index 72c79b0..d2bcbc2 100644 --- a/Peercord Source/src/p2p/modules/messaging.js +++ b/Peercord Source/src/p2p/modules/messaging.js @@ -7,32 +7,37 @@ export function getAllMessages(network) { return Array.from(network.messages.values()).filter(m => { const ch = m.payload.channel; - if (ch && ch.length > 64 && ch[64] === '-') { - const topicHex = ch.substring(0, 64); - const chName = ch.substring(65); - if (!joinedTopics.has(topicHex)) return false; - - const server = network.servers.find(s => s.topicHex === topicHex); - if (server && network.myKey !== server.owner && network.myKey !== ADMIN_PUBLIC_KEY) { - const userRoles = server.memberRoles?.[network.myKey] || []; - const isServerAdmin = userRoles.some(rId => { - const r = server.roles?.find(role => role.id === rId); - return r && r.permissions.includes('admin'); - }); + if (!m.recipient && ch) { + if (ch.length > 64 && ch[64] === '-') { + const topicHex = ch.substring(0, 64); + const chName = ch.substring(65); + if (!joinedTopics.has(topicHex)) return false; - if (!isServerAdmin) { - const channelPerms = server.channels?.permissions?.[chName]; - if (channelPerms && channelPerms.length > 0) { - const hasChannelAccess = userRoles.some(rId => channelPerms.includes(rId)); - if (!hasChannelAccess) return false; - } - - const hasReadPerm = userRoles.some(rId => { + const server = network.servers.find(s => s.topicHex === topicHex); + if (server && network.myKey !== server.owner && network.myKey !== ADMIN_PUBLIC_KEY) { + const userRoles = server.memberRoles?.[network.myKey] || []; + const isServerAdmin = userRoles.some(rId => { const r = server.roles?.find(role => role.id === rId); - return r && r.permissions.includes('read_messages'); + return r && r.permissions.includes('admin'); }); - if (!hasReadPerm && server.roles && server.roles.length > 0) return false; + + if (!isServerAdmin) { + const channelPerms = server.channels?.permissions?.[chName]; + if (channelPerms && channelPerms.length > 0) { + const hasChannelAccess = userRoles.some(rId => channelPerms.includes(rId)); + if (!hasChannelAccess) return false; + } + + const hasReadPerm = userRoles.some(rId => { + const r = server.roles?.find(role => role.id === rId); + return r && r.permissions.includes('read_messages'); + }); + if (!hasReadPerm && server.roles && server.roles.length > 0) return false; + } } + } else if (ch.length === 64) { + // Group chat: Filter out messages for group chats we are not in + if (!joinedTopics.has(ch)) return false; } } return true; @@ -352,50 +357,61 @@ export async function processMessage(network, msg) { } if (type === 'chat' || type === 'file') { - let canAccept = true; + let canAccept = false; + if (channel && channel.length > 64 && channel[64] === '-') { const topicHex = channel.substring(0, 64); const chName = channel.substring(65); const server = network.servers.find(s => s.topicHex === topicHex); - if (server && msg.sender !== server.owner && msg.sender !== ADMIN_PUBLIC_KEY) { - const userRoles = server.memberRoles?.[msg.sender] || []; - const isServerAdmin = userRoles.some(rId => { - const r = server.roles?.find(role => role.id === rId); - return r && r.permissions.includes('admin'); - }); - - if (!isServerAdmin) { - const channelPerms = server.channels?.permissions?.[chName]; - if (channelPerms && channelPerms.length > 0) { - const hasChannelAccess = userRoles.some(rId => channelPerms.includes(rId)); - if (!hasChannelAccess) canAccept = false; - } + + if (server) { + canAccept = true; + if (msg.sender !== server.owner && msg.sender !== ADMIN_PUBLIC_KEY) { + const userRoles = server.memberRoles?.[msg.sender] || []; + const isServerAdmin = userRoles.some(rId => { + const r = server.roles?.find(role => role.id === rId); + return r && r.permissions.includes('admin'); + }); - if (canAccept) { - const channelSendPerms = server.channels?.send_permissions?.[chName]; - if (channelSendPerms && channelSendPerms.length > 0) { - const hasChannelSendAccess = userRoles.some(rId => channelSendPerms.includes(rId)); - if (!hasChannelSendAccess) canAccept = false; + if (!isServerAdmin) { + const channelPerms = server.channels?.permissions?.[chName]; + if (channelPerms && channelPerms.length > 0) { + const hasChannelAccess = userRoles.some(rId => channelPerms.includes(rId)); + if (!hasChannelAccess) canAccept = false; } - } - - if (canAccept) { - const hasSendPerm = userRoles.some(rId => { - const r = server.roles?.find(role => role.id === rId); - return r && r.permissions.includes('send_messages'); - }); - if (!hasSendPerm && server.roles && server.roles.length > 0) canAccept = false; - - if (type === 'file') { - const hasFilePerm = userRoles.some(rId => { + + if (canAccept) { + const channelSendPerms = server.channels?.send_permissions?.[chName]; + if (channelSendPerms && channelSendPerms.length > 0) { + const hasChannelSendAccess = userRoles.some(rId => channelSendPerms.includes(rId)); + if (!hasChannelSendAccess) canAccept = false; + } + } + + if (canAccept) { + const hasSendPerm = userRoles.some(rId => { const r = server.roles?.find(role => role.id === rId); - return r && r.permissions.includes('send_files'); + return r && r.permissions.includes('send_messages'); }); - if (!hasFilePerm && server.roles && server.roles.length > 0) canAccept = false; + if (!hasSendPerm && server.roles && server.roles.length > 0) canAccept = false; + + if (type === 'file') { + const hasFilePerm = userRoles.some(rId => { + const r = server.roles?.find(role => role.id === rId); + return r && r.permissions.includes('send_files'); + }); + if (!hasFilePerm && server.roles && server.roles.length > 0) canAccept = false; + } } } } } + } else if (channel && channel.length === 64) { + // Group chat: Only accept if we are actually in this group chat + const gc = network.servers.find(s => s.topicHex === channel && s.isGroupChat); + if (gc) { + canAccept = true; + } } if (canAccept && !network.deletedMessages.has(id) && !network.messages.has(id)) { @@ -459,6 +475,7 @@ export async function sendDMRequest(network, targetKey, profile) { await network.db.put('dm:' + targetKey, network.dms[targetKey]); if (network.onDMsUpdate) network.onDMsUpdate({ ...network.dms }); await _appendEncryptedMessage(network, targetKey, { type: 'dm_request', profile: { displayName: network.displayName, username: network.username, avatar: network.avatar, bio: network.bio, connections: network.connections } }); + network._broadcastIdentity(); } export async function acceptDMRequest(network, targetKey) { @@ -468,6 +485,7 @@ export async function acceptDMRequest(network, targetKey) { if (network.onDMsUpdate) network.onDMsUpdate({ ...network.dms }); } await _appendEncryptedMessage(network, targetKey, { type: 'dm_accept' }); + network._broadcastIdentity(); } export async function sendMessage(network, channel, text, replyTo = null) { @@ -493,7 +511,9 @@ export async function sendReaction(network, targetId, emoji, isDM = false, targe export function sendEphemeral(network, payload) { if (!network.swarm) return; const msg = b4a.from(JSON.stringify({ type: 'ephemeral', payload })); - for (const { conn } of network.peers.values()) conn.write(msg); + for (const { conn } of network.peers.values()) { + try { conn.write(msg); } catch(e) {} + } } export function sendOffline(network) { sendEphemeral(network, { type: 'offline' }); }