gotosocial/internal/uris/uri.go

538 lines
18 KiB
Go
Raw Permalink Normal View History

// GoToSocial
// Copyright (C) GoToSocial Authors admin@gotosocial.org
// SPDX-License-Identifier: AGPL-3.0-or-later
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
package uris
import (
"fmt"
"net/url"
"strings"
2021-09-01 18:29:25 +02:00
"code.superseriousbusiness.org/gotosocial/internal/config"
"code.superseriousbusiness.org/gotosocial/internal/regexes"
)
const (
[feature] Support new model of interaction flow for forward compat with v0.21.0 (#4394) ~~Still WIP!~~ This PR allows v0.20.0 of GtS to be forward-compatible with the interaction request / authorization flow that will fully replace the current flow in v0.21.0. Basically, this means we need to recognize LikeRequest, ReplyRequest, and AnnounceRequest, and in response to those requests, deliver either a Reject or an Accept, with the latter pointing towards a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization, respectively. This can then be used by the remote instance to prove to third parties that the interaction has been accepted by the interactee. These Authorization types need to be dereferencable to third parties, so we need to serve them. As well as recognizing the above "polite" interaction request types, we also need to still serve appropriate responses to "impolite" interaction request types, where an instance that's unaware of interaction policies tries to interact with a post by sending a reply, like, or boost directly, without wrapping it in a WhateverRequest type. Doesn't fully close https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 but gets damn near (just gotta update the federating with GtS documentation). Migrations tested on both Postgres and SQLite. Co-authored-by: kim <grufwub@gmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4394 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-14 15:37:35 +02:00
UsersPath = "users" // UsersPath is for serving users info
StatusesPath = "statuses" // StatusesPath is for serving statuses
InboxPath = "inbox" // InboxPath represents the activitypub inbox location
OutboxPath = "outbox" // OutboxPath represents the activitypub outbox location
FollowersPath = "followers" // FollowersPath represents the activitypub followers location
FollowingPath = "following" // FollowingPath represents the activitypub following location
LikedPath = "liked" // LikedPath represents the activitypub liked location
CollectionsPath = "collections" // CollectionsPath represents the activitypub collections location
FeaturedPath = "featured" // FeaturedPath represents the activitypub featured location
PublicKeyPath = "main-key" // PublicKeyPath is for serving an account's public key
FollowPath = "follow" // FollowPath used to generate the URI for an individual follow or follow request
UpdatePath = "updates" // UpdatePath is used to generate the URI for an account update
BlocksPath = "blocks" // BlocksPath is used to generate the URI for a block
MovesPath = "moves" // MovesPath is used to generate the URI for a move
ReportsPath = "reports" // ReportsPath is used to generate the URI for a report/flag
ConfirmEmailPath = "confirm_email" // ConfirmEmailPath is used to generate the URI for an email confirmation link
FileserverPath = "fileserver" // FileserverPath is a path component for serving attachments + media
EmojiPath = "emoji" // EmojiPath represents the activitypub emoji location
TagsPath = "tags" // TagsPath represents the activitypub tags location
AcceptsPath = "accepts" // AcceptsPath represents the activitypub Accept's location
AuthorizationsPath = "authorizations" // AuthorizationsPath represents the location of an Authorization type such as LikeAuthorization, ReplyAuthorization, etc.
RejectsPath = "rejects" // RejectsPath represents the activitypub Reject's location
)
// UserURIs contains a bunch of UserURIs
// and URLs for a user, host, account, etc.
type UserURIs struct {
// The web URL of the instance
// host, eg https://example.org
HostURL string
// The web URL of the user,
// eg., https://example.org/@example_user
UserURL string
// The web URL for statuses of this user,
// eg., https://example.org/@example_user/statuses
StatusesURL string
// The activitypub URI of this user,
// eg., https://example.org/users/example_user
UserURI string
// The activitypub URI for this user's statuses,
// eg., https://example.org/users/example_user/statuses
StatusesURI string
// The activitypub URI for this user's activitypub inbox,
// eg., https://example.org/users/example_user/inbox
InboxURI string
// The activitypub URI for this user's activitypub outbox,
// eg., https://example.org/users/example_user/outbox
OutboxURI string
// The activitypub URI for this user's followers,
// eg., https://example.org/users/example_user/followers
FollowersURI string
// The activitypub URI for this user's following,
// eg., https://example.org/users/example_user/following
FollowingURI string
// The activitypub URI for this user's liked posts.
// eg., https://example.org/users/example_user/liked
LikedURI string
// The activitypub URI for this user's featured collections,
// eg., https://example.org/users/example_user/collections/featured
FeaturedCollectionURI string
// The URI for this user's public key,
// eg., https://example.org/users/example_user/publickey
PublicKeyURI string
}
// GenerateURIForFollow returns the AP URI for a new follow -- something like:
// https://example.org/users/whatever_user/follow/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForFollow(username string, thisFollowID string) string {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
FollowPath,
thisFollowID,
)
}
// GenerateURIForLike returns the AP URI for a new like/fave -- something like:
// https://example.org/users/whatever_user/liked/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForLike(username string, thisFavedID string) string {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
LikedPath,
thisFavedID,
)
2021-05-28 22:47:18 +02:00
}
// GenerateURIForUpdate returns the AP URI for a new update activity -- something like:
// https://example.org/users/whatever_user#updates/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForUpdate(username string, thisUpdateID string) string {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
UpdatePath,
thisUpdateID,
)
}
// GenerateURIForBlock returns the AP URI for a new block activity -- something like:
// https://example.org/users/whatever_user/blocks/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForBlock(username string, thisBlockID string) string {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
BlocksPath,
thisBlockID,
)
}
// GenerateURIForMove returns the AP URI for a new Move activity -- something like:
// https://example.org/users/whatever_user/moves/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForMove(username string, thisMoveID string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
MovesPath,
thisMoveID,
)
}
// GenerateURIForReport returns the API URI for a new Flag activity -- something like:
// https://example.org/reports/01GP3AWY4CRDVRNZKW0TEAMB5R
//
// This path specifically doesn't contain any info about the user who did the reporting,
// to protect their privacy.
func GenerateURIForReport(thisReportID string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL2(proto,
host,
ReportsPath,
thisReportID,
)
}
// GenerateURIForEmailConfirm returns a link for email confirmation -- something like:
// https://example.org/confirm_email?token=490e337c-0162-454f-ac48-4b22bb92a205
func GenerateURIForEmailConfirm(token string) string {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
return buildURL1(proto, host, ConfirmEmailPath) + "?token=" + token
}
// GenerateURIForAccept returns the AP URI for a new Accept activity -- something like:
// https://example.org/users/whatever_user/accepts/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForAccept(username string, thisAcceptID string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
AcceptsPath,
thisAcceptID,
)
}
[feature] Support new model of interaction flow for forward compat with v0.21.0 (#4394) ~~Still WIP!~~ This PR allows v0.20.0 of GtS to be forward-compatible with the interaction request / authorization flow that will fully replace the current flow in v0.21.0. Basically, this means we need to recognize LikeRequest, ReplyRequest, and AnnounceRequest, and in response to those requests, deliver either a Reject or an Accept, with the latter pointing towards a LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization, respectively. This can then be used by the remote instance to prove to third parties that the interaction has been accepted by the interactee. These Authorization types need to be dereferencable to third parties, so we need to serve them. As well as recognizing the above "polite" interaction request types, we also need to still serve appropriate responses to "impolite" interaction request types, where an instance that's unaware of interaction policies tries to interact with a post by sending a reply, like, or boost directly, without wrapping it in a WhateverRequest type. Doesn't fully close https://codeberg.org/superseriousbusiness/gotosocial/issues/4026 but gets damn near (just gotta update the federating with GtS documentation). Migrations tested on both Postgres and SQLite. Co-authored-by: kim <grufwub@gmail.com> Reviewed-on: https://codeberg.org/superseriousbusiness/gotosocial/pulls/4394 Co-authored-by: tobi <tobi.smethurst@protonmail.com> Co-committed-by: tobi <tobi.smethurst@protonmail.com>
2025-09-14 15:37:35 +02:00
// GenerateURIForAuthorization returns the AP URI for a new Authorization object,
// ie., LikeAuthorization, ReplyAuthorization, or AnnounceAuthorization.
// Eg., https://example.org/users/whatever_user/authorizations/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForAuthorization(username string, id string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
AuthorizationsPath,
id,
)
}
// GenerateURIForReject returns the AP URI for a new Reject activity -- something like:
// https://example.org/users/whatever_user/rejects/01F7XTH1QGBAPMGF49WJZ91XGC
func GenerateURIForReject(username string, thisRejectID string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL4(proto,
host,
UsersPath,
username,
RejectsPath,
thisRejectID,
)
}
// GenerateURIsForAccount throws together a bunch of URIs
// for the given username, with the given protocol and host.
func GenerateURIsForAccount(username string) UserURIs {
proto := config.GetProtocol()
[chore] Global server configuration overhaul (#575) * move config flag names and usage to config package, rewrite config package to use global Configuration{} struct Signed-off-by: kim <grufwub@gmail.com> * improved code comment Signed-off-by: kim <grufwub@gmail.com> * linter Signed-off-by: kim <grufwub@gmail.com> * fix unmarshaling Signed-off-by: kim <grufwub@gmail.com> * remove kim's custom go compiler changes Signed-off-by: kim <grufwub@gmail.com> * generate setter and flag-name functions, implement these in codebase Signed-off-by: kim <grufwub@gmail.com> * update deps Signed-off-by: kim <grufwub@gmail.com> * small change Signed-off-by: kim <grufwub@gmail.com> * appease the linter... Signed-off-by: kim <grufwub@gmail.com> * move configuration into ConfigState structure, ensure reloading to/from viper settings to keep in sync Signed-off-by: kim <grufwub@gmail.com> * lint Signed-off-by: kim <grufwub@gmail.com> * update code comments Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * fix merge issue Signed-off-by: kim <grufwub@gmail.com> * improved version string (removes time + go version) Signed-off-by: kim <grufwub@gmail.com> * fix version string build to pass test script + consolidate logic in func Signed-off-by: kim <grufwub@gmail.com> * add license text, update config.Defaults comment Signed-off-by: kim <grufwub@gmail.com> * add license text to generated config helpers file Signed-off-by: kim <grufwub@gmail.com> * defer unlock on config.Set___(), to ensure unlocked on panic Signed-off-by: kim <grufwub@gmail.com> * make it more obvious which cmd flags are being attached Signed-off-by: kim <grufwub@gmail.com>
2022-05-30 13:41:24 +01:00
host := config.GetHost()
// URLs for serving web requests.
hostURL := proto + "://" + host
userURL := hostURL + "/@" + username
statusesURL := userURL + "/" + StatusesPath
// the below URIs are used in ActivityPub and Webfinger
userURI := hostURL + "/" + UsersPath + "/" + username
statusesURI := userURI + "/" + StatusesPath
inboxURI := userURI + "/" + InboxPath
outboxURI := userURI + "/" + OutboxPath
followersURI := userURI + "/" + FollowersPath
followingURI := userURI + "/" + FollowingPath
likedURI := userURI + "/" + LikedPath
collectionURI := userURI + "/" + CollectionsPath + "/" + FeaturedPath
publicKeyURI := userURI + "/" + PublicKeyPath
return UserURIs{
HostURL: hostURL,
UserURL: userURL,
StatusesURL: statusesURL,
UserURI: userURI,
StatusesURI: statusesURI,
InboxURI: inboxURI,
OutboxURI: outboxURI,
FollowersURI: followersURI,
FollowingURI: followingURI,
LikedURI: likedURI,
FeaturedCollectionURI: collectionURI,
PublicKeyURI: publicKeyURI,
}
}
// URIForAttachment generates a URI for
// an attachment/emoji/header etc.
//
// Will produce something like:
//
// "https://example.org/fileserver/01FPST95B8FC3HG3AGCDKPQNQ2/attachment/original/01FPST9QK4V5XWS3F9Z4F2G1X7.gif"
func URIForAttachment(
accountID string,
mediaType string,
mediaSize string,
mediaID string,
extension string,
) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL5(proto,
host,
FileserverPath,
accountID,
mediaType,
mediaSize,
mediaID,
) + "." + extension
}
// StoragePathForAttachment generates a storage
// path for an attachment/emoji/header etc.
//
// Will produce something like:
//
// "01FPST95B8FC3HG3AGCDKPQNQ2/attachment/original/01FPST9QK4V5XWS3F9Z4F2G1X7.gif"
func StoragePathForAttachment(
accountID string,
mediaType string,
mediaSize string,
mediaID string,
extension string,
) string {
return buildPath4(
accountID,
mediaType,
mediaSize,
mediaID,
) + "." + extension
}
// URIForEmoji generates an
// ActivityPub URI for an emoji.
//
// Will produce something like:
//
// "https://example.org/emoji/01FPST9QK4V5XWS3F9Z4F2G1X7"
func URIForEmoji(emojiID string) string {
proto := config.GetProtocol()
host := config.GetHost()
return buildURL2(proto,
host,
EmojiPath,
emojiID,
)
}
// URIForTag generates an activitypub uri for a tag.
func URIForTag(name string) string {
proto := config.GetProtocol()
host := config.GetHost()
name = strings.ToLower(name)
return buildURL2(proto,
host,
TagsPath,
name,
)
}
// IsUserPath returns true if the given URL path corresponds to eg /users/example_username
func IsUserPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.UserPath.MatchString(id.Path)
}
// IsUserWebPath returns true if the given URL path corresponds to eg /@example_username
func IsUserWebPath(id *url.URL) bool {
return regexes.UserWebPath.MatchString(id.Path)
}
// IsInboxPath returns true if the given URL path corresponds to eg /users/example_username/inbox
func IsInboxPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.InboxPath.MatchString(id.Path)
}
// IsOutboxPath returns true if the given URL path corresponds to eg /users/example_username/outbox
func IsOutboxPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.OutboxPath.MatchString(id.Path)
}
// IsFollowersPath returns true if the given URL path corresponds to eg /users/example_username/followers
func IsFollowersPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.FollowersPath.MatchString(id.Path)
}
// IsFollowingPath returns true if the given URL path corresponds to eg /users/example_username/following
func IsFollowingPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.FollowingPath.MatchString(id.Path)
}
// IsFollowPath returns true if the given URL path corresponds to eg /users/example_username/follow/SOME_ULID_OF_A_FOLLOW
func IsFollowPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.FollowPath.MatchString(id.Path)
}
// IsLikedPath returns true if the given URL path corresponds to eg /users/example_username/liked
func IsLikedPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.LikedPath.MatchString(id.Path)
}
// IsLikePath returns true if the given URL path corresponds to eg /users/example_username/liked/SOME_ULID_OF_A_STATUS
func IsLikePath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.LikePath.MatchString(id.Path)
}
// IsStatusesPath returns true if the given URL path corresponds to eg /users/example_username/statuses/SOME_ULID_OF_A_STATUS
func IsStatusesPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.StatusesPath.MatchString(id.Path)
}
2021-06-26 16:21:40 +02:00
// IsPublicKeyPath returns true if the given URL path corresponds to eg /users/example_username/main-key
func IsPublicKeyPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.PublicKeyPath.MatchString(id.Path)
2021-06-26 16:21:40 +02:00
}
// IsBlockPath returns true if the given URL path corresponds to eg /users/example_username/blocks/SOME_ULID_OF_A_BLOCK
func IsBlockPath(id *url.URL) bool {
2021-09-01 18:29:25 +02:00
return regexes.BlockPath.MatchString(id.Path)
}
// IsReportPath returns true if the given URL path corresponds to eg /reports/SOME_ULID_OF_A_REPORT
func IsReportPath(id *url.URL) bool {
return regexes.ReportPath.MatchString(id.Path)
}
// IsAcceptsPath returns true if the given URL path corresponds to eg /users/example_username/accepts/SOME_ULID_OF_AN_ACCEPT
func IsAcceptsPath(id *url.URL) bool {
return regexes.AcceptsPath.MatchString(id.Path)
}
// ParseStatusesPath returns the username and ulid from a path such as /users/example_username/statuses/SOME_ULID_OF_A_STATUS
func ParseStatusesPath(id *url.URL) (username string, ulid string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.StatusesPath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
}
username = matches[1]
ulid = matches[2]
return
}
// ParseUserPath returns the username from a path such as /users/example_username
func ParseUserPath(id *url.URL) (username string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.UserPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseUserPath returns the username from a path such as /@example_username
func ParseUserWebPath(id *url.URL) (username string, err error) {
matches := regexes.UserWebPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseInboxPath returns the username from a path such as /users/example_username/inbox
func ParseInboxPath(id *url.URL) (username string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.InboxPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseOutboxPath returns the username from a path such as /users/example_username/outbox
func ParseOutboxPath(id *url.URL) (username string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.OutboxPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseFollowersPath returns the username from a path such as /users/example_username/followers
func ParseFollowersPath(id *url.URL) (username string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.FollowersPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseFollowingPath returns the username from a path such as /users/example_username/following
func ParseFollowingPath(id *url.URL) (username string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.FollowingPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
username = matches[1]
return
}
// ParseLikedPath returns the username and ulid from a path such as /users/example_username/liked/SOME_ULID_OF_A_STATUS
func ParseLikedPath(id *url.URL) (username string, ulid string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.LikePath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
}
username = matches[1]
ulid = matches[2]
return
}
// ParseBlockPath returns the username and ulid from a path such as /users/example_username/blocks/SOME_ULID_OF_A_BLOCK
func ParseBlockPath(id *url.URL) (username string, ulid string, err error) {
2021-09-01 18:29:25 +02:00
matches := regexes.BlockPath.FindStringSubmatch(id.Path)
if len(matches) != 3 {
err = fmt.Errorf("expected 3 matches but matches length was %d", len(matches))
return
}
username = matches[1]
ulid = matches[2]
return
}
// ParseReportPath returns the ulid from a path such as /reports/SOME_ULID_OF_A_REPORT
func ParseReportPath(id *url.URL) (ulid string, err error) {
matches := regexes.ReportPath.FindStringSubmatch(id.Path)
if len(matches) != 2 {
err = fmt.Errorf("expected 2 matches but matches length was %d", len(matches))
return
}
ulid = matches[1]
return
}