common

package
v0.0.0-...-80710a0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 1, 2025 License: BSD-2-Clause Imports: 33 Imported by: 0

Documentation

Index

Constants

View Source
const Cost = 10

Cost is the cost of the bcrypt digest. This is hard-coded at 10 to match the value that Rails/Devise uses. We're porting a Rails database and we want to be able to use existing passwords instead of forcing users to reset them.

View Source
const EncryptedTokenPrefix = "$2a$10$"

EncryptedTokenPrefix is the prefix that should appear on all our encrypted passwords and tokens in the database. Note that it depends on common.Cost being set to 10.

Variables

View Source
var ErrAccountDeactivated = errors.New("account deactivated")

ErrAccountDeactivated means the user logged in to a deactivated account.

View Source
var ErrActiveFiles = errors.New("cannot delete object with active files")

ErrActiveFiles occurs when we try to delete an IntellectualObject that has active files. All of the object's files should first be deleted (set to State = "D").

View Source
var ErrAlreadyHasAuthyID = errors.New("user is already registered with authy")

ErrAlreadyHasAuthyID occurs when we try to register a user with Authy and they already have an Authy ID.

View Source
var ErrCountTypeNotSupported = errors.New("type is not supported for view count")

ErrCountTypeNotSupported indicates that we cannot get counts for the given type from the *_counts views. Use a regular SQL count() instead.

View Source
var ErrCrossOriginReferer = errors.New("csrf error: cross origin request forbidden")

ErrMissingReferer means we got a cross-site request on an unsafe methods such as POST, PUT, DELETE. See the CSRF middleware.

View Source
var ErrDecodeCookie = errors.New("error decoding cookie")

ErrDecodeCookie occurs when we get a bad authentication cookie. We consider it a 400/Bad Request because we don't set bad cookies.

View Source
var ErrIDMismatch = errors.New("resource or institution id mismatch")

ErrIDMismatch can indicate that the specified resource does not belong to the specified institition, or (more likely) that resource/institution IDs in a URL do not match resource/institution IDs submitted in the PUT/POST body of an HTML request.

View Source
var ErrIdentifierChange = errors.New("identifier cannot change")

ErrIdentifierChange occurs when someone tries to change the identifier of a resource.

View Source
var ErrInstIDChange = errors.New("institution id cannot change")

ErrInstIDChange occurs when someone tries to change the institution id of a resource.

View Source
var ErrInternal = errors.New("internal server error")

ErrInternal is a runtime error that is not the user's fault, hence probably the programmer's fault.

View Source
var ErrInvalidAPICredentials = errors.New("invalid api credentials")

ErrInvalidAPICredentials means the user supplied the wrong email or API token while trying to access a REST API endpoint.

View Source
var ErrInvalidCSRFToken = errors.New("invalid csrf token")

ErrInvalidCSRFToken is specifically for POST/PUT/DELETE where we have a missing or invalid CSRF token.

View Source
var ErrInvalidLogin = errors.New("invalid login or password")

ErrInvalidLogin means the user supplied the wrong login name or password while trying to sign in.

View Source
var ErrInvalidObjectID = errors.New("one or more object ids is invalid")

ErrInvalidObjectID occurs when requesting a batch deletion that contains one or more invalid object ids.

View Source
var ErrInvalidParam = errors.New("invalid parameter")

ErrInvalidParam means the HTTP request contained an invalid parameter.

View Source
var ErrInvalidRequestorID = errors.New("invalid requestor id")

ErrInvalidRequestorID occurs when APTrust admin submits batch delete request on behalf of a user who is not allowed to initiate a batch deletion.

View Source
var ErrInvalidToken = errors.New("invalid token")

ErrInvalidToken means that the token presented for an action like password reset or deletion confirmation does not match the encrypted token in the database. When this error occurs, the user may not proceed with the requested action.

View Source
var ErrMissingReferer = errors.New("csrf error: missing http referer")

ErrMissingReferer means the request had no http referer header, so we can't tell where it came from. We can't tell for sure if it's a cross-origin attack, so we throw an error. This happens only on unsafe methods (POST, PUT, DELETE). See the CSRF middleware.

View Source
var ErrMustCompleteReset = errors.New("you must complete your own password reset")

ErrMustCompleteReset occurs when a user is supposed to be resetting their own password but tries instead to reset someone else's. SysAdmin and Inst admins can legitimately reset others' passwords, but they shouldn't be doing it in this context.

View Source
var ErrNoAuthyID = errors.New("user does not have an authy id")

ErrNoAuthyID occurs when a user requests two-factor login via Authy but does not have an Authy ID.

View Source
var ErrNotSignedIn = errors.New("user is not signed in")

ErrNotSignedIn means user has not signed in.

View Source
var ErrNotSupported = errors.New("operation not supported")

ErrNotSupported is an internal error that occurs, for example, when we try to delete an object that does not support deletion. This represents a programmer error and should not occur.

View Source
var ErrParentRecordNotFound = errors.New("parent record not found")

ErrParentRecordNotFound occurs when we cannot find the parent record required to check a user's permission. For example, when a user requests a Checksum, we first need to know if the user is allowed to access the Checksum's parent, which is a Generic File. If that record is missing, we get this error.

View Source
var ErrPasswordReqs = errors.New("password does not meet minimum requirements")

ErrPasswordReqs indicates that the password the user is trying to set does not meet minimum requirements.

View Source
var ErrPendingWorkItems = errors.New("task cannot be completed because this object has pending work items")

ErrPendingWorkItems occurs when a user wants to restore or delete an object or file but the WorkItems list shows other operations are pending on that item. For example, we can't delete or restore an object or file while another version of that object/file is pending ingest. Doing so would cause newly ingested files to be deleted as soon as they're sent to preservation, or would cause a restoration to contain a mix of new and old versions of a bag's files.

View Source
var ErrPermissionDenied = errors.New("permission denied")

ErrPermissionDenied means the user tried to access a resource withouth sufficient permission.

View Source
var ErrRequestAlreadyApproved = errors.New("this request has already been approved")

ErrRequestAlreadyApproved occurs when someone tries to approve or cancel a request that was previously approved.

View Source
var ErrRequestAlreadyCancelled = errors.New("this request has already been cancelled")

ErrRequestAlreadyCancelled occurs when someone tries to approve or cancel a request that was previously cancelled.

View Source
var ErrResourcePermission = errors.New("cannot determine permission type for requested requested resource")

ErrResourcePermission occurs when Authorization middleware cannot determine which permission is required to access the specified resoruce.

View Source
var ErrStorageOptionChange = errors.New("cannot change storage option on active object")

ErrStorageOptionChange indicates someone tried to change the storage option on an active object. (It's OK to change storage option on a deleted object that you are re-depositing.)

View Source
var ErrSubclassMustImplement = errors.New("subclass must implement this method")

ErrSubclassMustImplement indicates that a subclass has not implemented a method inherited from a base class.

View Source
var ErrWrongAPI = errors.New("non-admins must use the member api")

ErrWrongAPI occurs when a non-admin user tries to access the admin API. While the member and admin APIs share some common handlers, and members do technically have access to a number of read-only operations in both APIs, we don't want members to get in the habit of accessing the wrong endpoints.

View Source
var ErrWrongDataType = errors.New("wrong data type")

ErrWrongDataType occurs when the user submits data of the wrong type, such string data that cannot be converted to a number, bool, date, or whatever type the application is expecting.

View Source
var TextTemplates map[string]*template.Template

Functions

func ComparePasswords

func ComparePasswords(hashed, plaintext string) bool

ComparePasswords compares a plaintext password against a hashed password, returning true if they match, false otherwise.

func ConsoleDebug

func ConsoleDebug(message string, args ...interface{})

ConsoleDebug prints a message to the console if the following we are running in the dev or test environment and we are not running automated tests. We want to see these messages in the console when we're doing interactive testing in the dev or test environments, but NOT when running automated tests because they clutter the test output.

We also don't want these messages to appear in production, which is why we have a hard-coded list of safe environment names.

func CopyFile

func CopyFile(src string, dst string, mode os.FileMode) error

CopyFile copies the file at src path to dst path. It applies the permissions specified in mode to the destination file. Mode values are 0644, 0755, etc.

func CountryCodeAndPhone

func CountryCodeAndPhone(phoneNumber string) (int32, string, error)

CountryCodeAndPhone returns the country code and phone number for a phoneNumber in format that begins with plus country code, e.g. "+12125551212"

func EncryptPassword

func EncryptPassword(password string) (string, error)

EncryptPassword returns the password run through bcrypt 2a with the specified salt and cost.

func ExpandTilde

func ExpandTilde(filePath string) (string, error)

Expands the tilde in a directory path to the current user's home directory. For example, on Linux, ~/data would expand to something like /home/josie/data

func FileExists

func FileExists(path string) bool

Returns true if the file at path exists, false if not.

func Hash

func Hash(plaintext string) string

Hash returns an encrypted version of plaintext that cannot be decrypted. This is suitable for encrypting passwords, reset-tokens, etc. The combined use of md5 plus plaintext salt plus sha256 provides some protection against rainbow tables.

TODO: Delete this if we're not using it. Looks like we're actually using bcrypt in common/password.go

func InterfaceList

func InterfaceList(items []string) []interface{}

InterfaceList converts a list of strings to a list of interfaces.

func IsEmptyString

func IsEmptyString(str string) bool

IsEmptyString returns true if str, stripped of leading and trailing whitespace, is empty.

func IsTrueString

func IsTrueString(s string) bool

IsTrueString returns true if param s is "true", "yes", or "1". The test is case-insensitive. Use this for parsing query string params.

func ListIsEmpty

func ListIsEmpty(list []string) bool

ListIsEmpty returns true if the slice contains no elements, or if all the elements are empty strings.

func LoadRelativeFile

func LoadRelativeFile(relpath string) ([]byte, error)

LoadRelativeFile loads the file at the specified path relative to ProjectRoot() and returns the contents as a byte array.

Example:

bytes, err := LoadRelativeFile("db/fixtures/work_items.csv")

func LooksEncrypted

func LooksEncrypted(s string) bool

LooksEncrypted returns true if string s looks like it's been through our EncryptePassword fuction. We use LooksEncrypted on some pgmodels to ensure we're not saving unencrypted passwords or tokens.

func LooksLikeUUID

func LooksLikeUUID(uuid string) bool

LooksLikeUUID returns true if uuid looks like a valid UUID.

func NewOTP

func NewOTP() (string, error)

NewOTP returns a six-digit code suitable for use as a one-time password. We return this as a string because we need to store a hashed version in the DB and then send a copy to the user.

func PasswordMeetsRequirements

func PasswordMeetsRequirements(pwd string) bool

PasswordMeetsRequirements returns true if param pwd meets our minimum password requirements.

func PrintAndExit

func PrintAndExit(message string)

PrintAndExit prints a message to STDERR and exits

func ProjectRoot

func ProjectRoot() string

ProjectRoot returns the project root.

func RandomToken

func RandomToken() string

RandomToken returns a string of random hex digits suitable for use as a secure token.

func SanitizeIdentifier

func SanitizeIdentifier(str string) string

SanitizeIdentifier strips everything but letters, numbers, underscores periods and double quotes from str. This is used primarily to sanitize SQL column names in queries. Column names may include things like "email", "user"."email", etc.

func SplitCamelCase

func SplitCamelCase(str string, max int) []string

SplitCamelCase splits camel-case identifiers into multiple words. Note that it does not split on multiple consecutive caps, so param CurrencyUSD would return ["Currency", "USD"].

If max is less than zero, this will split into all words. If max is > 0, this will split into max words.

func TestsAreRunning

func TestsAreRunning() bool

TestsAreRunning returns true when code is running under "go test"

func ToHumanSize

func ToHumanSize(size, unit int64) string

ToHumanSize converts a raw byte count (size) to a human-friendly representation.

Types

type APTContext

type APTContext struct {

	// Config contains config information for the entire app.
	Config *Config

	// DB is our connection to the Postgres/RDS database.
	DB *pg.DB

	// Log is our logger.
	Log zerolog.Logger

	// AuthyClient sends push notifications to users who have enabled
	// two-factor auth via push.
	AuthyClient network.AuthyClientInterface

	// NSQClient lets registry queue work items for preservation services
	// and lets us view NSQ admin stats.
	NSQClient *network.NSQClient

	// RedisClient talks to Redis/Elasticache to retrieve info about
	// WorkItems in progress.
	RedisClient *network.RedisClient

	// SESClient is for sending emails from behind a NAT gateway
	SESClient *network.SESClient

	// SNSClient sends two-factor auth codes via Text/SMS message
	// to user phones.
	SNSClient *network.SNSClient

	// SMTPClient is for sending emails from a private subnet that
	// is not using a NAT gateway.
	SMTPClient *network.SMTPClient
}

func Context

func Context() *APTContext

Context returns an APTContext object, which includes global config settings and a connection to the postgres database. It requires the environment variable APT_ENV to be set to something valid, such as "test", "dev", "integration", "demo", "staging" or "production". It loads the .env file that corresponds to that setting. If APT_ENV is not set to a valid setting, the app dies immediately.

This will also exit if the app cannot connect to the database. If that happens, ensure the database is running and accepting connections at the specified location, and ensure that the db credentials are correct.

func (*APTContext) SendEmail

func (c *APTContext) SendEmail(recipientEmail, subject, message string) error

type Config

type Config struct {
	Cookies          *CookieConfig
	DB               *DBConfig
	EnvName          string
	Logging          *LoggingConfig
	NsqUrl           string
	TwoFactor        *TwoFactorConfig
	Email            *EmailConfig
	Redis            *RedisConfig
	RetentionMinimum *RetentionMinimum

	// BatchDeletionKey is a secret loaded from parameter store.
	// Batch deletion requests must include this as an extra security token.
	BatchDeletionKey string

	// MaintenanceMode indicates whether we're currently doing maintenance
	// on the system. If this is true, all requests will be redirected to
	// the /maintenance page, which will render HTML or JSON as necessary.
	// Also, when this is true, the cron jobs in application/cron.go will
	// not be initialized, so that the DB will receive no writes from Registry
	// and will be free to run migrations.
	MaintenanceMode bool

	// EmailServiceType describes which email service to use in the current
	// environment. This should be "SMTP" if we're running on a private
	// subnet with no NAT gateway. Otherwise, it should be "SES". If this is
	// not set, or if it's set to an invalid value, it defaults to SMTP.
	EmailServiceType string
}

func NewConfig

func NewConfig() *Config

Returns a new config based on APT_ENV

func (*Config) BucketQualifier

func (config *Config) BucketQualifier() string

BucketQualifier returns the S3 bucket qualifier for the current config. We could set this in the .env file, but we want to avoid the possibility of a config pointing to the wrong buckets. (For example, by someone carelessly copying and pasting config settings.) Our restrictive IAM permissions prevent the wrong environments from accessing the wrong buckets, but this is an extra layer of protection. This defaults to ".test", so if anything is misconfigured, we'll be reading from and writing to buckets in which we explicitly guarantee no permanance.

func (*Config) HTTPScheme

func (config *Config) HTTPScheme() string

HTTPScheme returns "http" for the dev, test, ci, and travis environments. It returns "https" for all other environments.

func (*Config) IsTestOrDevEnv

func (config *Config) IsTestOrDevEnv() bool

Returns true if we're in a test or dev environment.

func (*Config) ToJSON

func (config *Config) ToJSON() (string, error)

ToJSON serializes the config to JSON for logging purposes. It omits some sensitive data, such as the Pharos API key and AWS credentials.

type CookieConfig

type CookieConfig struct {
	Secure        *securecookie.SecureCookie
	Domain        string
	HTTPSOnly     bool
	MaxAge        int
	SessionCookie string
	FlashCookie   string
	PrefsCookie   string
}

type DBConfig

type DBConfig struct {
	Host     string
	Name     string
	User     string
	Password string
	Port     int
	Driver   string
	UseSSL   bool
}

DBConfig contains info for connecting to the Postgres database.

type EmailConfig

type EmailConfig struct {
	AWSRegion   string
	Enabled     bool
	FromAddress string
	SesUser     string
	SesPassword string
	SesEndpoint string
}

EmailConfig describes how to connect to Amazon SES or another SMTP service. If SesEndpoint is empty, we'll use the default public SES endpoint for the specified region. If non-empty, we'll use the explicit SesEndpoint. Should be non-empty if we're on a private subnet without a NAT gateway.

type LoggingConfig

type LoggingConfig struct {
	File         string
	Level        zerolog.Level
	LogCaller    bool
	LogToConsole bool
	LogSql       bool
}

type Pager

type Pager struct {
	TotalItems       int
	ItemsInResultSet int
	ItemFirst        int
	ItemLast         int
	Page             int
	PerPage          int
	QueryOffset      int
	PreviousLink     string
	NextLink         string
	URL              *url.URL
}

func NewPager

func NewPager(c *gin.Context, baseURL string, defaultPerPage int) (*Pager, error)

func (*Pager) SetCounts

func (pager *Pager) SetCounts(totalItems, itemsInResultSet int)

type QueryLogger

type QueryLogger struct {
	// contains filtered or unexported fields
}

func NewQueryLogger

func NewQueryLogger(logger zerolog.Logger) *QueryLogger

func (*QueryLogger) AfterQuery

func (l *QueryLogger) AfterQuery(c context.Context, qe *pg.QueryEvent) error

func (*QueryLogger) BeforeQuery

func (l *QueryLogger) BeforeQuery(c context.Context, qe *pg.QueryEvent) (context.Context, error)

type RedisConfig

type RedisConfig struct {
	URL       string
	Password  string
	DefaultDB int
}

type RetentionMinimum

type RetentionMinimum struct {
	Glacier     int
	GlacierDeep int
	Wasabi      int
	Standard    int
}

RetentionMinimum describes the minimum number of days items must remain in preservation storage before they can be deleted. For S3 and APTrust Standard storage, this is zero. We can delete those items at any time. All other storage types have restrictions. We prevent depositors from deleting items that have not met the minimum retention period because we have to pay for the minimum retention period no matter what, and we need to pass those costs through to depositors.

func (*RetentionMinimum) For

func (rm *RetentionMinimum) For(storageOption string) int

For returns the minimum number of days an object or file must be stored in the specified storage option. (RetentionMinimum.For(option) makes for readable code.)

type TwoFactorConfig

type TwoFactorConfig struct {
	AuthyEnabled  bool
	AuthyAPIKey   string
	AWSRegion     string
	SMSEnabled    bool
	OTPExpiration time.Duration
	SNSUser       string
	SNSPassword   string
	SNSEndpoint   string
}

TwoFactorConfig contains info for sending push messages through Authy and SMS text messages through AWS SNS. If SNSEndpoint is empty, we'll use the default public SNS endpoint for the specified region. If non-empty, we'll use the explicit SNSEndpoint. Should be non-empty if we're on a private subnet without a NAT gateway.

type ValidationError

type ValidationError struct {
	Errors map[string]string
}

func NewValidationError

func NewValidationError() *ValidationError

func (*ValidationError) Error

func (v *ValidationError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL