package domain import ( "fmt" "math" "strings" ) // officialUpdatesChannelMention is the public @username of the updates channel // linked from the welcome message. It is carried both in the template text and // in a MessageEntityMention so clients render it as a tappable link. const officialUpdatesChannelMention = "@ziodotsh" const officialWelcomeMessageTemplate = "👋 Welcome to OwpenGram!\n\nYou just signed in via %s.\n\nIf this wasn't you, revoke this session from \"Settings > Privacy and Security > Active sessions\" immediately.\n\nIf you haven't already, feel free to join " + officialUpdatesChannelMention + " for all the latest updates!" // OfficialWelcomeMessage builds the account-visible incoming message sent // from the official system account on every completed sign-in (SignUp and // every subsequent SignIn/SignInWithEmail), regardless of delivery channel. // Unlike OfficialLoginCodeMessage this never embeds a secret, so it is safe // to send unconditionally — it exists to give the account owner (and, on a // self-hosted single-admin server, that's usually also "the admin") a // visible record of every session start. func OfficialWelcomeMessage(userID int64, method string, date int) (Message, error) { method = strings.TrimSpace(method) if userID <= 0 || IsSystemUserID(userID) || method == "" || date < 0 || date > math.MaxInt32 { return Message{}, fmt.Errorf("%w: user=%d method=%q date=%d", ErrLoginCodeDeliveryInvalid, userID, method, date) } body := fmt.Sprintf(officialWelcomeMessageTemplate, method) msg := Message{ OwnerUserID: userID, Peer: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID}, From: Peer{Type: PeerTypeUser, ID: OfficialSystemUserID}, Date: date, Body: body, } if ent, ok := usernameMentionEntity(body, officialUpdatesChannelMention); ok { msg.Entities = []MessageEntity{ent} } return msg, nil } // usernameMentionEntity locates mention ("@name") in text and returns a // MessageEntityMention spanning it, with the UTF-16 offset/length clients expect. func usernameMentionEntity(text, mention string) (MessageEntity, bool) { before, _, found := strings.Cut(text, mention) if !found { return MessageEntity{}, false } return MessageEntity{ Type: MessageEntityMention, Offset: utf16Len(before), Length: utf16Len(mention), }, true } func utf16Len(s string) int { n := 0 for _, r := range s { n++ if r > 0xffff { n++ } } return n } // SignInMethodLabel returns the human-readable method name embedded in // OfficialWelcomeMessage. Email-signup accounts are identified by // SignupEmail (see NewEmailSignupDisplayPhone) rather than by their stored // Phone, which — once assigned — is an ordinary-looking short number that // carries no information about the signup method. func SignInMethodLabel(u User) string { if u.SignupEmail != "" { return "email" } return "phone number" }