0
0
Fork 0

Change Web Push API deliveries to use request pooling (#16014)

This commit is contained in:
Eugen Rochko 2021-04-12 14:25:34 +02:00 committed by GitHub
parent 463875f645
commit 120965eb0b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 150 additions and 58 deletions

View file

@ -24,81 +24,80 @@ class Web::PushSubscription < ApplicationRecord
validates :key_p256dh, presence: true
validates :key_auth, presence: true
def push(notification)
I18n.with_locale(associated_user&.locale || I18n.default_locale) do
push_payload(payload_for_notification(notification), 48.hours.seconds)
end
delegate :locale, to: :associated_user
def encrypt(payload)
Webpush::Encryption.encrypt(payload, key_p256dh, key_auth)
end
def audience
@audience ||= Addressable::URI.parse(endpoint).normalized_site
end
def crypto_key_header
p256ecdsa = vapid_key.public_key_for_push_header
"p256ecdsa=#{p256ecdsa}"
end
def authorization_header
jwt = JWT.encode({ aud: audience, exp: 24.hours.from_now.to_i, sub: "mailto:#{contact_email}" }, vapid_key.curve, 'ES256', typ: 'JWT')
"WebPush #{jwt}"
end
def pushable?(notification)
data&.key?('alerts') && ActiveModel::Type::Boolean.new.cast(data['alerts'][notification.type.to_s])
ActiveModel::Type::Boolean.new.cast(data&.dig('alerts', notification.type.to_s))
end
def associated_user
return @associated_user if defined?(@associated_user)
@associated_user = if user_id.nil?
session_activation.user
else
user
end
@associated_user = begin
if user_id.nil?
session_activation.user
else
user
end
end
end
def associated_access_token
return @associated_access_token if defined?(@associated_access_token)
@associated_access_token = if access_token_id.nil?
find_or_create_access_token.token
else
access_token.token
end
@associated_access_token = begin
if access_token_id.nil?
find_or_create_access_token.token
else
access_token.token
end
end
end
class << self
def unsubscribe_for(application_id, resource_owner)
access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil)
.pluck(:id)
access_token_ids = Doorkeeper::AccessToken.where(application_id: application_id, resource_owner_id: resource_owner.id, revoked_at: nil).pluck(:id)
where(access_token_id: access_token_ids).delete_all
end
end
private
def push_payload(message, ttl = 5.minutes.seconds)
Webpush.payload_send(
message: Oj.dump(message),
endpoint: endpoint,
p256dh: key_p256dh,
auth: key_auth,
ttl: ttl,
ssl_timeout: 10,
open_timeout: 10,
read_timeout: 10,
vapid: {
subject: "mailto:#{::Setting.site_contact_email}",
private_key: Rails.configuration.x.vapid_private_key,
public_key: Rails.configuration.x.vapid_public_key,
}
)
end
def payload_for_notification(notification)
ActiveModelSerializers::SerializableResource.new(
notification,
serializer: Web::NotificationSerializer,
scope: self,
scope_name: :current_push_subscription
).as_json
end
def find_or_create_access_token
Doorkeeper::AccessToken.find_or_create_for(
application: Doorkeeper::Application.find_by(superapp: true),
resource_owner: session_activation.user_id,
resource_owner: user_id || session_activation.user_id,
scopes: Doorkeeper::OAuth::Scopes.from_string('read write follow push'),
expires_in: Doorkeeper.configuration.access_token_expires_in,
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
)
end
def vapid_key
@vapid_key ||= Webpush::VapidKey.from_keys(Rails.configuration.x.vapid_public_key, Rails.configuration.x.vapid_private_key)
end
def contact_email
@contact_email ||= ::Setting.site_contact_email
end
end