email/worker: add more context to errors
For instance, failure to open the private PGP key would just fail
with an unhelpful "panic: open : no such file or directory" error.
database: add helpers to fetch all columns
The current solution of fetching columns based on the GraphQL context
has some limits. While probably not the solution for all use-cases, it
sometimes can be desirable to simply fetch all columns from the database
when retrieving objects.
This commit adds two simple functions doing just that. They can be used
when building SQL queries, like
query := database.SelectAll(new(model.Email))
and
rows.Scan(database.ScanAll(&email)...)
auth: Use canonical user IDs
When adding users to the database, use the canonical user ID from
meta.sr.ht.
webhooks.FilterWebhooks: Filter by user_id
Normalize remote address before saving to context
One cause for https://todo.sr.ht/~sircmpwn/meta.sr.ht/193 was that code
performing this sanitization was in multiple places, and a fix was not
applied in all places. There is no reasonable expectation for the port
to be present anyways, e.g. if the address is taken from a trusted
reverse proxy's header. Hence, perform the normalization here, so that
the code doing this in applications can be simplified.
Note that this does not yet fix the below ticket, it will just make the
fix easier.
References: https://todo.sr.ht/~sircmpwn/meta.sr.ht/193
email.EnqueueStd: Don't overwrite headers
Sometimes we need to specify the Message-Id, From, and Reply-To headers
(e.g. for todo.sr.ht ticket notifications). Don't overwrite these
headers if they are present.
email: handle failure to encrypt notifications
Currently, failure to encrypt the notification email - e.g. due to an
expired key - will make the entire request fail. Instead, fall back to
sending an unencrypted email and let the request succeed (unless that
fails also, which is unlikely).
valid: Add Error function
Add an Error function which is similar to Errorf except that it does not
take a format specifier.
webhooks: Execute GraphQL queries synchronously
Execute GraphQL webhook queries synchronously instead of in a background
task to avoid race conditions.
Fix (some) user PGP key lookups from meta.sr.ht
The authForUsername() function uses a closure that is almost identical
to the LookupUser() function, but is missing the handling for the PGP
key if called from meta.sr.ht. This causes at least the email
notifications for new OAuth2 tokens to be sent unencrypted. This commit
fixes that (and reduces code duplication) by calling LookupUser()
instead.
This requires the context for the tests to have a value for the calling
service, so add that to the mock.
valid: Add NullableString
Add a NullableString method to allow users to differentiate between the
absence of a field and an explicitly provided null value.
valid: Add Errorf function
Add an Errorf function to create GraphQL errors without a validation
context.
database: always include table name in SELECT
When JOINs are performed on the auto-generated SELECT query,
multiple tables may have the same field names. For instance, in
lists.sr.ht the "list" and "subscription" tables both have an "id"
column. When performing a "mailingLists" GraphQL query this results
in this error:
pq: column reference "id" is ambiguous
The old query looks like this:
SELECT "description", "name", "id", "owner_id", "updated", COALESCE(
access.permissions,
CASE WHEN list.owner_id = $1
THEN $2
ELSE CASE WHEN sub.id IS NOT NULL
THEN list.subscriber_permissions
ELSE null END
END,
list.nonsubscriber_permissions | list.account_permissions), access.id AS access_id, sub.id AS subscription_id FROM list LEFT JOIN access ON
access.list_id = list.id AND
access.user_id = $3 LEFT JOIN subscription sub ON
sub.list_id = list.id AND
sub.user_id = $4 WHERE list.owner_id = $5 ORDER BY "updated" DESC LIMIT 26
The new query looks like this:
SELECT "description", "name", "list"."id", "list"."owner_id", "list"."updated", COALESCE(
access.permissions,
CASE WHEN list.owner_id = $1
THEN $2
ELSE CASE WHEN sub.id IS NOT NULL
THEN list.subscriber_permissions
ELSE null END
END,
list.nonsubscriber_permissions | list.account_permissions), access.id AS access_id, sub.id AS subscription_id FROM list LEFT JOIN access ON
access.list_id = list.id AND
access.user_id = $3 LEFT JOIN subscription sub ON
sub.list_id = list.id AND
sub.user_id = $4 WHERE list.owner_id = $5 ORDER BY "updated" DESC LIMIT 26
webhooks: Add FilterWebhooks function