@namespace("keybase.1") protocol user { import idl "common.avdl"; record TrackProof { string proofType; string proofName; string idString; } record WebProof { string hostname; array protocols; } record Proofs { array social; array web; array publicKeys; } record UserSummary { UID uid; string username; string fullName; union { null, LinkID } linkID; } record UserSummarySet { array users; Time time; int version; } /** listTracking gets verified data from the tracking statements in the user's sigchain. However, it does not check to make sure the tracked users have not reset since the track statement. If assertion is empty, it will use the current logged in user. */ UserSummarySet listTracking(int sessionID, string filter, string assertion); string listTrackingJSON(int sessionID, string filter, boolean verbose, string assertion); /** listTrackersUnverified returns the users following the given user, and is unverified and server-trust. */ UserSummarySet listTrackersUnverified(int sessionID, string assertion); @typedef("string") record EmailAddress {} record Email { EmailAddress email; boolean isVerified; boolean isPrimary; IdentityVisibility visibility; UnixTime lastVerifyEmailDate; } record UserSettings { array emails; array phoneNumbers; } /** Load a user from the server. */ User loadUser(int sessionID, UID uid); User loadUserByName(int sessionID, string username); /** Load a user + device keys from the server. */ UserPlusKeys loadUserPlusKeys(int sessionID, UID uid, KID pollForKID); UserPlusKeysV2AllIncarnations loadUserPlusKeysV2( int sessionID, UID uid, KID pollForKID, OfflineAvailability oa ); /** Load public keys for a user. */ array loadPublicKeys(int sessionID, UID uid); /** Load my public keys (for logged in user). */ array loadMyPublicKeys(int sessionID); /** Load user settings (for logged in user). */ UserSettings loadMySettings(int sessionID); /** Load all the user's public keys (even those in reset key families) from the server with no verification */ array loadAllPublicKeysUnverified(int sessionID, UID uid); void profileEdit(int sessionID, string fullName, string location, string bio); record InterestingPerson { UID uid; string username; string fullname; map serviceMap; } array interestingPeople(int maxUsers, string namespace); UserVersion meUserVersion(int sessionID, boolean forcePoll); /** getUPAK returns a UPAK. Used mainly for debugging. */ @lint("ignore") UPAKVersioned getUPAK(UID uid, boolean unstubbed); /** getUPAKLite returns a UPKLiteV1AllIncarnations. Used mainly for debugging. */ @lint("ignore") UPKLiteV1AllIncarnations getUPAKLite(UID uid); void uploadUserAvatar(string filename, union { null, ImageCropRect } crop); ProofSuggestionsRes proofSuggestions(int sessionID); record ProofSuggestionsRes{ array suggestions; boolean showMore; } // A proof the user doesn't have. record ProofSuggestion { string key; boolean belowFold; string profileText; // "Prove your Twitter", "Add a PGP key" array profileIcon; array profileIconDarkmode; string pickerText; // "Twitter", "Your own website", "octodon.xyz" string pickerSubtext; // "twitter.com", "Mastodon instance" array pickerIcon; array pickerIconDarkmode; array metas; // for 'new' proof types } record NextMerkleRootRes { union { null, MerkleRootV2 } res; } /** FindNextMerkleRootAfterRevoke finds the first Merkle Root that contains the UID/KID revocation at the given SigChainLocataion. The MerkleRootV2 prev is a hint as to where we'll start our search. Usually it's the next one, but not always */ NextMerkleRootRes findNextMerkleRootAfterRevoke(UID uid, KID kid, SigChainLocation loc, MerkleRootV2 prev); /** FindNextMerkleRootAfterReset finds the first Merkle root that contains the UID reset at resetSeqno. You should pass it prev, which was the last known Merkle root at the time of the reset. Usually, we'll just turn up the next Merkle root, but not always. */ NextMerkleRootRes findNextMerkleRootAfterReset(UID uid, Seqno resetSeqno, ResetMerkleRoot prev); /** PassphraseState values are used in .config.json, so should not be changed without a migration strategy */ enum PassphraseState { KNOWN_0, RANDOM_1 } record CanLogoutRes { boolean canLogout; string reason; PassphraseState passphraseState; } CanLogoutRes canLogout(int sessionID); PassphraseState loadPassphraseState(int sessionID); union { null, UserCard } userCard(int sessionID, string username, boolean useSession); // user.passphrase_state gregor message body @lint("ignore") record UserPassphraseStateMsg { @jsonkey("state") PassphraseState passphraseState; } record UserBlockedRow { @jsonkey("block_uid") UID uid; @jsonkey("block_username") string username; @jsonkey("chat") union { null, boolean } chat; @jsonkey("follow") union { null, boolean } follow; } enum UserBlockType { CHAT_0, FOLLOW_1 } // user.blocked gregor message body record UserBlockedBody { @jsonkey("blocks") array blocks; // The user who blocked (should be the currently logged-in user). @jsonkey("blocker_uid") UID uid; @jsonkey("blocker_username") string username; } record UserBlockState { UserBlockType blockType; boolean blocked; } record UserBlockedSummary { string blocker; map> blocks; } // User Blocking record UserBlock { string username; boolean chatBlocked; boolean followBlocked; union { null, Time } createTime; union { null, Time } modifyTime; } record UserBlockArg { string username; union { null, boolean } setChatBlock; union { null, boolean } setFollowBlock; } void setUserBlocks(int sessionID, array blocks); array getUserBlocks(int sessionID, array usernames); void reportUser(int sessionID, string username, string reason, string comment, boolean includeTranscript, union { null, string } convID); void dismissBlockButtons(TLFID tlfID); // Legacy user blocking: void blockUser(string username); void unblockUser(string username); // Team blocking record TeamBlock { @jsonkey("fq_name") string teamName; @jsonkey("ctime") Time createTime; } array getTeamBlocks(int sessionID); }