Page MenuHomePhorge

D15185.1765044518.diff
No OneTemporary

Size
18 KB
Referenced Files
None
Subscribers
None

D15185.1765044518.diff

diff --git a/lib/shared/threads/farcaster-group-spec.js b/lib/shared/threads/farcaster-group-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/threads/farcaster-group-spec.js
@@ -0,0 +1,15 @@
+// @flow
+
+import { farcasterThreadProtocol } from './protocols/farcaster-thread-protocol.js';
+import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
+
+const farcasterGroupSpec: ThreadSpec<MemberInfoSansPermissions> = Object.freeze(
+ {
+ traits: new Set(),
+ protocol: () => farcasterThreadProtocol,
+ threadLabel: 'Farcaster Group',
+ },
+);
+
+export { farcasterGroupSpec };
diff --git a/lib/shared/threads/farcaster-personal-spec.js b/lib/shared/threads/farcaster-personal-spec.js
new file mode 100644
--- /dev/null
+++ b/lib/shared/threads/farcaster-personal-spec.js
@@ -0,0 +1,14 @@
+// @flow
+
+import { farcasterThreadProtocol } from './protocols/farcaster-thread-protocol.js';
+import type { ThreadSpec } from './thread-spec.js';
+import type { MemberInfoSansPermissions } from '../../types/minimally-encoded-thread-permissions-types.js';
+
+const farcasterPersonalSpec: ThreadSpec<MemberInfoSansPermissions> =
+ Object.freeze({
+ traits: new Set(['personal']),
+ protocol: () => farcasterThreadProtocol,
+ threadLabel: 'Farcaster Personal',
+ });
+
+export { farcasterPersonalSpec };
diff --git a/lib/shared/threads/protocols/dm-thread-protocol.js b/lib/shared/threads/protocols/dm-thread-protocol.js
--- a/lib/shared/threads/protocols/dm-thread-protocol.js
+++ b/lib/shared/threads/protocols/dm-thread-protocol.js
@@ -51,7 +51,7 @@
import {
assertWithValidator,
pendingThickSidebarURLPrefix,
- thickIDRegex,
+ thickIDRegExp,
} from '../../../utils/validation-utils.js';
import { generatePendingThreadColor } from '../../color-utils.js';
import {
@@ -890,7 +890,7 @@
}: ThreadJoinPayload);
},
- threadIDMatchesProtocol: (threadID: string) => thickIDRegex.test(threadID),
+ threadIDMatchesProtocol: (threadID: string) => thickIDRegExp.test(threadID),
allowsDeletingSidebarSource: false,
diff --git a/lib/shared/threads/protocols/farcaster-thread-protocol.js b/lib/shared/threads/protocols/farcaster-thread-protocol.js
--- a/lib/shared/threads/protocols/farcaster-thread-protocol.js
+++ b/lib/shared/threads/protocols/farcaster-thread-protocol.js
@@ -22,7 +22,10 @@
ChangeThreadSettingsPayload,
ThreadJoinPayload,
} from '../../../types/thread-types.js';
-import { pendingThickSidebarURLPrefix } from '../../../utils/validation-utils.js';
+import {
+ farcasterThreadIDRegExp,
+ pendingThickSidebarURLPrefix,
+} from '../../../utils/validation-utils.js';
import { messageNotifyTypes } from '../../messages/message-spec.js';
import type { ThreadProtocol } from '../thread-spec.js';
@@ -129,7 +132,7 @@
},
threadIDMatchesProtocol: (threadID: string): boolean => {
- return threadID.startsWith('FARCASTER#');
+ return farcasterThreadIDRegExp.test(threadID);
},
allowsDeletingSidebarSource: false,
diff --git a/lib/shared/threads/protocols/keyserver-thread-protocol.js b/lib/shared/threads/protocols/keyserver-thread-protocol.js
--- a/lib/shared/threads/protocols/keyserver-thread-protocol.js
+++ b/lib/shared/threads/protocols/keyserver-thread-protocol.js
@@ -69,9 +69,8 @@
SendMessageError,
} from '../../../utils/errors.js';
import {
- isSchemaRegExp,
pendingSidebarURLPrefix,
- thickIDRegex,
+ isKeyserverThreadID,
} from '../../../utils/validation-utils.js';
import { generatePendingThreadColor } from '../../color-utils.js';
import { getNextLocalID } from '../../id-utils.js';
@@ -646,7 +645,7 @@
},
threadIDMatchesProtocol: (threadID: string) => {
- return isSchemaRegExp.test(threadID) && !thickIDRegex.test(threadID);
+ return isKeyserverThreadID(threadID);
},
allowsDeletingSidebarSource: true,
diff --git a/lib/shared/threads/thread-specs.js b/lib/shared/threads/thread-specs.js
--- a/lib/shared/threads/thread-specs.js
+++ b/lib/shared/threads/thread-specs.js
@@ -6,6 +6,8 @@
import { communityRootSpec } from './community-root-spec.js';
import { communitySecretAnnouncementSubthreadSpec } from './community-secret-announcement-subthread-spec.js';
import { communitySecretSubthreadSpec } from './community-secret-subthread-spec.js';
+import { farcasterGroupSpec } from './farcaster-group-spec.js';
+import { farcasterPersonalSpec } from './farcaster-personal-spec.js';
import { genesisPersonalSpec } from './genesis-personal-spec.js';
import { genesisPrivateSpec } from './genesis-private-spec.js';
import { genesisSpec } from './genesis-spec.js';
@@ -38,6 +40,8 @@
[threadTypes.PERSONAL]: personalSpec,
[threadTypes.PRIVATE]: privateSpec,
[threadTypes.THICK_SIDEBAR]: thickSidebarSpec,
+ [threadTypes.FARCASTER_PERSONAL]: farcasterPersonalSpec,
+ [threadTypes.FARCASTER_GROUP]: farcasterGroupSpec,
});
let threadTypesByTrait = null;
diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js
--- a/lib/types/dm-ops.js
+++ b/lib/types/dm-ops.js
@@ -29,7 +29,7 @@
import { values } from '../utils/objects.js';
import {
tColor,
- thickIDRegex,
+ thickIDRegExp,
tRegex,
tShape,
tString,
@@ -59,7 +59,7 @@
});
export type DMOperationType = $Values<typeof dmOperationTypes>;
-const tThickID = tRegex(thickIDRegex);
+const tThickID = tRegex(thickIDRegExp);
// In CHANGE_THREAD_SETTINGS operation we're generating message IDs
// based on the prefix that is tThickID. A message with the generated ID
diff --git a/lib/types/message-types.js b/lib/types/message-types.js
--- a/lib/types/message-types.js
+++ b/lib/types/message-types.js
@@ -155,7 +155,7 @@
tNumber,
tShape,
tUserID,
- thickIDRegex,
+ thickIDRegExp,
} from '../utils/validation-utils.js';
const composableMessageTypes = new Set([
@@ -743,5 +743,5 @@
};
export function messageIDIsThick(messageID: string): boolean {
- return thickIDRegex.test(messageID);
+ return thickIDRegExp.test(messageID);
}
diff --git a/lib/types/thread-types-enum.js b/lib/types/thread-types-enum.js
--- a/lib/types/thread-types-enum.js
+++ b/lib/types/thread-types-enum.js
@@ -68,11 +68,18 @@
| NonSidebarThickThreadType
| SidebarThickThreadType;
-export type ThreadType = ThinThreadType | ThickThreadType;
+export const farcasterThreadTypes = Object.freeze({
+ FARCASTER_PERSONAL: 17,
+ FARCASTER_GROUP: 18,
+});
+export type FarcasterThreadType = $Values<typeof farcasterThreadTypes>;
+
+export type ThreadType = ThinThreadType | ThickThreadType | FarcasterThreadType;
export const threadTypes = Object.freeze({
...thinThreadTypes,
...thickThreadTypes,
+ ...farcasterThreadTypes,
});
export function assertThinThreadType(threadType: number): ThinThreadType {
@@ -110,6 +117,19 @@
values(thickThreadTypes),
);
+export function assertFarcasterThreadType(
+ threadType: number,
+): FarcasterThreadType {
+ invariant(
+ threadType === 17 || threadType === 18,
+ 'number is not FarcasterThreadType enum',
+ );
+ return threadType;
+}
+export const farcasterThreadTypeValidator: TRefinement<number> = tNumEnum(
+ values(farcasterThreadTypes),
+);
+
export function assertThreadType(threadType: number): ThreadType {
invariant(
threadType === 3 ||
@@ -125,7 +145,9 @@
threadType === 13 ||
threadType === 14 ||
threadType === 15 ||
- threadType === 16,
+ threadType === 16 ||
+ threadType === 17 ||
+ threadType === 18,
'number is not ThreadType enum',
);
return threadType;
diff --git a/lib/utils/validation-utils.js b/lib/utils/validation-utils.js
--- a/lib/utils/validation-utils.js
+++ b/lib/utils/validation-utils.js
@@ -112,13 +112,27 @@
// PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h
const uuidRegex =
'[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}';
-const idSchemaRegex = `(?:(?:[0-9]+|${uuidRegex})\\|)?(?:[0-9]+|${uuidRegex})`;
-const isSchemaRegExp: RegExp = new RegExp(`^${idSchemaRegex}$`);
+const thickIDRegExp: RegExp = new RegExp(`^${uuidRegex}$`);
+
+const farcasterThreadIDRegex = 'FARCASTER#(?:(?:[0-9a-z]+)|(?:[0-9]+-[0-9]+))';
+const farcasterThreadIDRegExp: RegExp = new RegExp(
+ `^${farcasterThreadIDRegex}$`,
+);
+
+const idSchemaRegex = `(?:${farcasterThreadIDRegex}|(?:(?:[0-9]+|${uuidRegex})\\|)?(?:[0-9]+|${uuidRegex}))`;
+const idSchemaRegExp: RegExp = new RegExp(`^${idSchemaRegex}$`);
+
+function isKeyserverThreadID(threadID: string): boolean {
+ return (
+ idSchemaRegExp.test(threadID) &&
+ !thickIDRegExp.test(threadID) &&
+ !farcasterThreadIDRegExp.test(threadID)
+ );
+}
const pendingSidebarURLPrefix = 'sidebar';
const pendingThickSidebarURLPrefix = 'dm_sidebar';
const pendingThreadIDRegex = `pending/(type[0-9]+/[0-9]+(\\+[0-9]+)*|(${pendingSidebarURLPrefix}|${pendingThickSidebarURLPrefix})/${idSchemaRegex})`;
-const thickIDRegex: RegExp = new RegExp(`^${uuidRegex}$`);
const chatNameMaxLength = 191;
const chatNameMinLength = 0;
@@ -155,9 +169,11 @@
pendingSidebarURLPrefix,
pendingThickSidebarURLPrefix,
pendingThreadIDRegex,
- thickIDRegex,
+ thickIDRegExp,
validChatNameRegex,
validChatNameRegexString,
chatNameMaxLength,
- isSchemaRegExp,
+ idSchemaRegExp,
+ farcasterThreadIDRegExp,
+ isKeyserverThreadID,
};
diff --git a/lib/utils/validation-utils.test.js b/lib/utils/validation-utils.test.js
--- a/lib/utils/validation-utils.test.js
+++ b/lib/utils/validation-utils.test.js
@@ -1,8 +1,12 @@
// @flow
import {
+ idSchemaRegExp,
tMediaMessagePhoto,
tMediaMessageVideo,
+ isKeyserverThreadID,
+ thickIDRegExp,
+ farcasterThreadIDRegExp,
tNumEnum,
} from './validation-utils.js';
import { threadTypes } from '../types/thread-types-enum.js';
@@ -139,4 +143,149 @@
).toBe(false);
});
});
+
+ describe('ID regex tests', () => {
+ describe('Keyserver ID regex', () => {
+ it('Should match compound IDs with keyserver components', () => {
+ expect(isKeyserverThreadID('256|123')).toBe(true);
+ expect(isKeyserverThreadID('123|456')).toBe(true);
+ expect(
+ isKeyserverThreadID('550e8400-e29b-41d4-a716-446655440000|456'),
+ ).toBe(true);
+ });
+
+ it('Should not match thick IDs (UUIDs)', () => {
+ expect(
+ isKeyserverThreadID('550e8400-e29b-41d4-a716-446655440000'),
+ ).toBe(false);
+ });
+
+ it('Should not match Farcaster IDs', () => {
+ expect(isKeyserverThreadID('FARCASTER#ef5a742bca')).toBe(false);
+ expect(isKeyserverThreadID('FARCASTER#12345-635')).toBe(false);
+ });
+
+ it('Should not match invalid formats', () => {
+ expect(isKeyserverThreadID('')).toBe(false);
+ expect(isKeyserverThreadID('abc')).toBe(false);
+ expect(isKeyserverThreadID('123abc')).toBe(false);
+ });
+ });
+
+ describe('Thick ID regex', () => {
+ it('Should match valid UUIDs', () => {
+ expect(thickIDRegExp.test('550e8400-e29b-41d4-a716-446655440000')).toBe(
+ true,
+ );
+ expect(thickIDRegExp.test('6ba7b810-9dad-11d1-80b4-00c04fd430c8')).toBe(
+ true,
+ );
+ expect(thickIDRegExp.test('12345678-1234-1234-1234-123456789abc')).toBe(
+ true,
+ );
+ });
+
+ it('Should not match keyserver IDs', () => {
+ expect(thickIDRegExp.test('256')).toBe(false);
+ expect(thickIDRegExp.test('1234567890')).toBe(false);
+ });
+
+ it('Should not match Farcaster IDs', () => {
+ expect(thickIDRegExp.test('FARCASTER#ef5a742bca')).toBe(false);
+ expect(thickIDRegExp.test('FARCASTER#12345-635')).toBe(false);
+ });
+
+ it('Should not match malformed UUIDs', () => {
+ expect(thickIDRegExp.test('550e8400-e29b-41d4-a716-44665544000')).toBe(
+ false,
+ );
+ expect(
+ thickIDRegExp.test('550e8400-e29b-41d4-a716-446655440000-extra'),
+ ).toBe(false);
+ expect(thickIDRegExp.test('550e8400-e29b-41d4-a716')).toBe(false);
+ });
+ });
+
+ describe('Farcaster ID regex', () => {
+ it('Should match group conversation', () => {
+ expect(farcasterThreadIDRegExp.test('FARCASTER#ef5a742bca')).toBe(true);
+ expect(farcasterThreadIDRegExp.test('FARCASTER#abc123')).toBe(true);
+ expect(farcasterThreadIDRegExp.test('FARCASTER#0123456789abcdef')).toBe(
+ true,
+ );
+ });
+
+ it('Should match 1:1 conversation', () => {
+ expect(farcasterThreadIDRegExp.test('FARCASTER#12345-635')).toBe(true);
+ expect(farcasterThreadIDRegExp.test('FARCASTER#1-2')).toBe(true);
+ expect(farcasterThreadIDRegExp.test('FARCASTER#111111-999999')).toBe(
+ true,
+ );
+ });
+
+ it('Should not match keyserver IDs', () => {
+ expect(farcasterThreadIDRegExp.test('256')).toBe(false);
+ expect(farcasterThreadIDRegExp.test('1234567890')).toBe(false);
+ });
+
+ it('Should not match thick IDs', () => {
+ expect(
+ farcasterThreadIDRegExp.test('550e8400-e29b-41d4-a716-446655440000'),
+ ).toBe(false);
+ });
+
+ it('Should not match malformed Farcaster IDs', () => {
+ expect(farcasterThreadIDRegExp.test('farcaster')).toBe(false);
+ expect(farcasterThreadIDRegExp.test('FARCASTER#')).toBe(false);
+ expect(farcasterThreadIDRegExp.test('notFARCASTER#12345')).toBe(false);
+ });
+ });
+
+ describe('idSchemaRegex', () => {
+ it('Should match keyserver IDs', () => {
+ expect(idSchemaRegExp.test('256')).toBe(true);
+ expect(idSchemaRegExp.test('1234567890')).toBe(true);
+ expect(idSchemaRegExp.test('1')).toBe(true);
+ });
+
+ it('Should match thick IDs', () => {
+ expect(
+ idSchemaRegExp.test('550e8400-e29b-41d4-a716-446655440000'),
+ ).toBe(true);
+ expect(
+ idSchemaRegExp.test('6ba7b810-9dad-11d1-80b4-00c04fd430c8'),
+ ).toBe(true);
+ });
+
+ it('Should match Farcaster IDs', () => {
+ expect(idSchemaRegExp.test('FARCASTER#ef5a742bca')).toBe(true);
+ expect(idSchemaRegExp.test('FARCASTER#12345-635')).toBe(true);
+ });
+
+ it('Should match compound IDs with keyserver prefix', () => {
+ expect(
+ idSchemaRegExp.test('256|550e8400-e29b-41d4-a716-446655440000'),
+ ).toBe(true);
+ });
+
+ it('Should match compound IDs with UUID prefix', () => {
+ expect(
+ idSchemaRegExp.test('550e8400-e29b-41d4-a716-446655440000|256'),
+ ).toBe(true);
+ });
+
+ it('Should not match invalid formats', () => {
+ expect(idSchemaRegExp.test('')).toBe(false);
+ expect(idSchemaRegExp.test('invalid')).toBe(false);
+ expect(idSchemaRegExp.test('123abc')).toBe(false);
+ expect(idSchemaRegExp.test('farcaster')).toBe(false);
+ expect(idSchemaRegExp.test('550e8400-e29b-41d4-a716')).toBe(false);
+ });
+
+ it('Should not match multiple pipe separators', () => {
+ expect(idSchemaRegExp.test('256|123|456')).toBe(false);
+ expect(idSchemaRegExp.test('256||123')).toBe(false);
+ });
+ });
+ });
});
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.h
@@ -29,7 +29,6 @@
std::vector<MessageEntity>
processMessagesResults(SQLiteStatementWrapper &preparedSQL) const;
- std::string getThickThreadTypesList() const;
public:
SQLiteQueryExecutor(std::string sqliteFilePath, bool skipMigration = false);
diff --git a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
--- a/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
+++ b/native/cpp/CommonCpp/DatabaseManagers/SQLiteQueryExecutor.cpp
@@ -188,20 +188,6 @@
}
}
-std::string SQLiteQueryExecutor::getThickThreadTypesList() const {
- std::stringstream resultStream;
- for (auto it = THICK_THREAD_TYPES.begin(); it != THICK_THREAD_TYPES.end();
- ++it) {
- int typeInt = static_cast<int>(*it);
- resultStream << typeInt;
-
- if (it + 1 != THICK_THREAD_TYPES.end()) {
- resultStream << ",";
- }
- }
- return resultStream.str();
-}
-
std::vector<MessageEntity> SQLiteQueryExecutor::getInitialMessages() const {
static std::string getInitialMessagesSQL =
"SELECT "
diff --git a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h
--- a/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h
+++ b/native/cpp/CommonCpp/NativeModules/PersistentStorageUtilities/ThreadOperationsUtilities/ThreadTypeEnum.h
@@ -22,35 +22,41 @@
PERSONAL = 14,
PRIVATE = 15,
THICK_SIDEBAR = 16,
+ FARCASTER_PERSONAL = 17,
+ FARCASTER_GROUP = 18,
};
-const std::vector<ThreadType> THICK_THREAD_TYPES{
- ThreadType::LOCAL,
- ThreadType::PERSONAL,
- ThreadType::PRIVATE,
- ThreadType::THICK_SIDEBAR};
-
// Regex patterns - should be in sync with lib/utils/validation-utils.js
const std::string UUID_REGEX_STRING =
"[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{"
"12}";
-const std::string ID_SCHEMA_REGEX_STRING = "(?:(?:[0-9]+|" + UUID_REGEX_STRING +
- ")\\|)?(?:[0-9]+|" + UUID_REGEX_STRING + ")";
-
-const std::regex IS_SCHEMA_REGEX("^" + ID_SCHEMA_REGEX_STRING + "$");
+const std::string FARCASTER_ID_REGEX_STRING =
+ "FARCASTER#(?:(?:[0-9a-z]+)|(?:"
+ "[0-9]+-[0-9]+))";
+const std::string ID_SCHEMA_REGEX_STRING = "(?:" + FARCASTER_ID_REGEX_STRING +
+ "|(?:(?:[0-9]+|" + UUID_REGEX_STRING + ")\\|)?(?:[0-9]+|" +
+ UUID_REGEX_STRING + "))";
+
+const std::regex ID_SCHEMA_REGEX("^" + ID_SCHEMA_REGEX_STRING + "$");
const std::regex THICK_ID_REGEX("^" + UUID_REGEX_STRING + "$");
+const std::regex FARCASTER_ID_REGEX("^" + FARCASTER_ID_REGEX_STRING + "$");
// Helper functions for regex testing
inline bool isSchemaID(const std::string &threadID) {
- return std::regex_match(threadID, IS_SCHEMA_REGEX);
+ return std::regex_match(threadID, ID_SCHEMA_REGEX);
}
inline bool isThickID(const std::string &threadID) {
return std::regex_match(threadID, THICK_ID_REGEX);
}
+inline bool isFarcasterID(const std::string &threadID) {
+ return std::regex_match(threadID, FARCASTER_ID_REGEX);
+}
+
inline bool threadIDMatchesKeyserverProtocol(const std::string &threadID) {
- return isSchemaID(threadID) && !isThickID(threadID);
+ return isSchemaID(threadID) && !isThickID(threadID) &&
+ !isFarcasterID(threadID);
}
} // namespace comm
diff --git a/web/shared-worker/_generated/comm_query_executor.wasm b/web/shared-worker/_generated/comm_query_executor.wasm
index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000
GIT binary patch
literal 0
Hc$@<O00001
literal 0
Hc$@<O00001

File Metadata

Mime Type
text/plain
Expires
Sat, Dec 6, 6:08 PM (20 h, 58 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
5839301
Default Alt Text
D15185.1765044518.diff (18 KB)

Event Timeline