diff --git a/api/graph/resolver.go b/api/graph/resolver.go index 9926780..bcd9260 100644 --- a/api/graph/resolver.go +++ b/api/graph/resolver.go @@ -115,7 +115,8 @@ to this email. } } -func sendEmailNotification(ctx context.Context, message string) error { +func sendEmailNotification(ctx context.Context, + username, userEmail, message string, pgpKey *string) error { r := strings.NewReader(message) mr, err := mail.CreateReader(r) if err != nil { @@ -151,12 +152,11 @@ func sendEmailNotification(ctx context.Context, message string) error { return fmt.Errorf("missing or malformed subject") } - user := auth.ForContext(ctx) header.SetAddressList("To", []*mail.Address{ - &mail.Address{user.Username, user.Email}, + &mail.Address{username, userEmail}, }) - return email.EnqueueStd(ctx, header, p.Body, user.PGPKey) + return email.EnqueueStd(ctx, header, p.Body, pgpKey) } // Sends a security-related notice to the authorized user. diff --git a/api/graph/schema.graphqls b/api/graph/schema.graphqls index 6e0a130..9e65c37 100644 --- a/api/graph/schema.graphqls +++ b/api/graph/schema.graphqls @@ -519,13 +519,13 @@ type Mutation { clientSecret: String!, redirectUri: String): OAuthGrantRegistration @internal """ - Sends a notification email to the currently logged-in user. + Sends a notification email to the given user. The 'message' parameter must be a RFC 5322 compliant Internet message with the special requirement that it must not contain any recipients (i.e. no 'To', 'Cc', or 'Bcc' header). """ - sendEmailNotification(message: String!): Boolean! @internal + sendEmailNotification(username: String!, message: String!): Boolean! @anoninternal """ Deletes the authenticated user's account. diff --git a/api/graph/schema.resolvers.go b/api/graph/schema.resolvers.go index bc70c31..13ad024 100644 --- a/api/graph/schema.resolvers.go +++ b/api/graph/schema.resolvers.go @@ -1214,8 +1214,34 @@ func (r *mutationResolver) IssueOAuthGrant(ctx context.Context, authorization st } // SendEmailNotification is the resolver for the sendEmailNotification field. -func (r *mutationResolver) SendEmailNotification(ctx context.Context, message string) (bool, error) { - err := sendEmailNotification(ctx, message) +func (r *mutationResolver) SendEmailNotification(ctx context.Context, username string, message string) (bool, error) { + user, err := loaders.ForContext(ctx).UsersByName.Load(username) + if err != nil { + return false, err + } + if user == nil { + return false, fmt.Errorf("Email notification request to unknown user: %s", user) + } + var key *string + + if user.PGPKeyID != nil { + if err := database.WithTx(ctx, &sql.TxOptions{ + Isolation: 0, + ReadOnly: true, + }, func(tx *sql.Tx) error { + row := tx.QueryRowContext(ctx, ` + SELECT key + FROM "pgpkey" WHERE id = $1; + `, *user.PGPKeyID) + if err := row.Scan(&key); err != nil { + return err + } + return nil + }); err != nil { + return false, err + } + } + err = sendEmailNotification(ctx, user.Username, user.Email, message, key) return err == nil, err }