diff --git a/Gemfile b/Gemfile index 7f7da8c57fc106..2695a0be35e527 100644 --- a/Gemfile +++ b/Gemfile @@ -96,7 +96,7 @@ gem 'webpush', github: 'ClearlyClaire/webpush', ref: 'f14a4d52e201128b1b00245d11 gem 'webauthn', '~> 3.0' gem 'json-ld' -gem 'json-ld-preloaded', '~> 3.2' +gem 'json-ld-preloaded', '~> 3.3' gem 'rdf-normalize', '~> 0.5' gem 'private_address_check', '~> 0.5' diff --git a/Gemfile.lock b/Gemfile.lock index 34958703a9ff06..75fdd9ee7ce336 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -380,9 +380,9 @@ GEM multi_json (~> 1.15) rack (>= 2.2, < 4) rdf (~> 3.3) - json-ld-preloaded (3.2.2) - json-ld (~> 3.2) - rdf (~> 3.2) + json-ld-preloaded (3.3.0) + json-ld (~> 3.3) + rdf (~> 3.3) json-schema (4.0.0) addressable (>= 2.8) jsonapi-renderer (0.2.2) @@ -864,7 +864,7 @@ DEPENDENCIES i18n-tasks (~> 1.0) idn-ruby json-ld - json-ld-preloaded (~> 3.2) + json-ld-preloaded (~> 3.3) json-schema (~> 4.0) kaminari (~> 1.2) kt-paperclip (~> 7.2) diff --git a/README.FLIPBOARD b/README.FLIPBOARD new file mode 100644 index 00000000000000..fe76d1b1158170 --- /dev/null +++ b/README.FLIPBOARD @@ -0,0 +1,17 @@ +- added updater_post_install.sh script +- added jenkins build script + +############## +# To sync fork +############## +$ git fetch upstream +$ git checkout main +$ git merge upstream/main +$ git push + +############## +# To get tags from upstream +############## +$ git fetch --tags upstream +$ git push --tags + diff --git a/app/controllers/api/v1/surf/accounts_controller.rb b/app/controllers/api/v1/surf/accounts_controller.rb new file mode 100644 index 00000000000000..0bdb4294dfc516 --- /dev/null +++ b/app/controllers/api/v1/surf/accounts_controller.rb @@ -0,0 +1,37 @@ +# frozen_string_literal: true + +class Api::V1::Surf::AccountsController < Api::BaseController + before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:create] + before_action :check_enabled_registrations, only: [:create] + + skip_before_action :require_authenticated_user!, only: :create + + def create + token = SurfAppSignUpService.new.call(doorkeeper_token.application, request.remote_ip, account_params) + response = Doorkeeper::OAuth::TokenResponse.new(token) + + headers.merge!(response.headers) + self.response_body = Oj.dump(response.body) + self.status = response.status + rescue ActiveRecord::RecordInvalid => e + render json: ValidationErrorFormatter.new(e, 'account.username': :username, 'invite_request.text': :reason).as_json, status: 422 + end + + private + + def account_params + params.permit(:username, :email, :password, :agreement, :locale, :reason, :time_zone) + end + + def check_enabled_registrations + forbidden if single_user_mode? || omniauth_only? || !allowed_registrations? + end + + def allowed_registrations? + Setting.registrations_mode != 'none' + end + + def omniauth_only? + ENV['OMNIAUTH_ONLY'] == 'true' + end +end diff --git a/app/controllers/api/v1/surf/emails_controller.rb b/app/controllers/api/v1/surf/emails_controller.rb new file mode 100644 index 00000000000000..7f9631e431ff0a --- /dev/null +++ b/app/controllers/api/v1/surf/emails_controller.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +class Api::V1::Surf::EmailsController < Api::BaseController + # Notes: + # - Requires an access token. + # - @current_user is the access token resource owner + before_action :current_user + + def confirmation + confirmation_params = { confirmation_token: @current_user.confirmation_token } + confirmation_url = "/auth/confirmation?#{confirmation_params.to_query}" + render json: { + base_url: request.base_url, + confirmation_url: confirmation_url, + username: @current_user.account.username, + email: @current_user.email, + } + end + + def welcome + render json: { + base_url: request.base_url, + username: @current_user.account.username, + email: @current_user.email, + } + end +end diff --git a/app/controllers/api/v1/surf/users_controller.rb b/app/controllers/api/v1/surf/users_controller.rb new file mode 100644 index 00000000000000..5ae94df9263b39 --- /dev/null +++ b/app/controllers/api/v1/surf/users_controller.rb @@ -0,0 +1,102 @@ +# frozen_string_literal: true + +class Api::V1::Surf::UsersController < Api::BaseController + before_action -> { doorkeeper_authorize! :write }, only: [:sign_in, :sign_out, :confirmation] + before_action -> { doorkeeper_authorize! :read } + before_action :require_user!, except: [:confirmation, :sign_in] + + def whoami + # Requires: user access_token + user = @current_user.as_json + user[:confirmation_token] = @current_user.confirmation_token unless @current_user.confirmed? + render json: user + end + + def sign_in + # Requires: app access_token + @current_user = User.find_by(email: params[:email]) + raise(ActiveRecord::RecordNotFound) unless @current_user&.valid_password?(params[:password]) + + require_not_suspended! + + # checks if they have an existing, valid access token + token = Doorkeeper::AccessToken.find_by( + resource_owner_id: @current_user.id, + application_id: doorkeeper_token.application, + revoked_at: nil + ) + if token.nil? + token = Doorkeeper::AccessToken.create!( + application: doorkeeper_token.application, + resource_owner_id: @current_user.id, + scopes: doorkeeper_token.application.scopes, + expires_in: Doorkeeper.configuration.access_token_expires_in, + use_refresh_token: Doorkeeper.configuration.refresh_token_enabled? + ) + end + + update_user_sign_in + prepare_returning_user! + + # prepare response + response = Doorkeeper::OAuth::TokenResponse.new(token) + headers.merge!(response.headers) + self.response_body = Oj.dump(response.body) + self.status = response.status + end + + def sign_out + # Requires: user access_token + revoke_access! + render json: { message: 'All access tokens revoked.' }, status: 200 + end + + def confirmation + # Requires: app access_token + # Requires: confirmation_token + confirmation_token = params[:confirmation_token] + raise Mastodon::InvalidParameterError, 'Missing confirmation_token' unless confirmation_token + + @current_user = User.find_first_by_auth_conditions(confirmation_token: confirmation_token) + raise(ActiveRecord::RecordNotFound) unless @current_user + + # update confirmed_at, reset confirmation_token + @current_user.update!( + confirmed_at: Time.current, + confirmation_token: nil + ) + prepare_new_user! + render json: { message: 'User confirmed.' }, status: 200 + end + + protected + + def revoke_access! + # this method revokes all tokens for the current user + Doorkeeper::AccessToken.by_resource_owner(@current_user).in_batches do |batch| + batch.update_all(revoked_at: Time.now.utc) # rubocop:disable Rails/SkipsModelValidations + end + end + + def require_user! + # Override require_user! because it prevents + # unconfirmed user access and might need to + # get the confirmation_token for sending the email + if current_user + update_user_sign_in + else + render json: { error: 'This method requires an authenticated user' }, status: 422 + end + end + + def prepare_new_user! + BootstrapTimelineWorker.perform_async(@current_user.account_id) + ActivityTracker.increment('activity:accounts:local') + ActivityTracker.record('activity:logins', @current_user.id) + TriggerWebhookWorker.perform_async('account.approved', 'Account', @current_user.account_id) + end + + def prepare_returning_user! + ActivityTracker.record('activity:logins', @current_user.id) + end +end diff --git a/app/controllers/auth/registrations_controller.rb b/app/controllers/auth/registrations_controller.rb index e70ae5b1b8b371..e7724e3e0afbbc 100644 --- a/app/controllers/auth/registrations_controller.rb +++ b/app/controllers/auth/registrations_controller.rb @@ -55,7 +55,7 @@ def build_resource(hash = nil) def configure_sign_up_params devise_parameter_sanitizer.permit(:sign_up) do |user_params| - user_params.permit({ account_attributes: [:username, :display_name], invite_request_attributes: [:text] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password) + user_params.permit({ account_attributes: [:username, :display_name], invite_request_attributes: [:text, :flipboard_username] }, :email, :password, :password_confirmation, :invite_code, :agreement, :website, :confirm_password) end end diff --git a/app/helpers/branding_helper.rb b/app/helpers/branding_helper.rb index 2b9c233c23bcfa..860934a3f80a65 100644 --- a/app/helpers/branding_helper.rb +++ b/app/helpers/branding_helper.rb @@ -11,7 +11,7 @@ def logo_as_symbol(version = :icon) end def _logo_as_symbol_wordmark - content_tag(:svg, tag.use(href: '#logo-symbol-wordmark'), viewBox: '0 0 261 66', class: 'logo logo--wordmark') + content_tag(:svg, tag.use(href: '#logo-symbol-wordmark'), viewBox: '0 0 500 500', class: 'logo logo--wordmark') end def _logo_as_symbol_icon diff --git a/app/javascript/images/app-icon.svg b/app/javascript/images/app-icon.svg index 1035bd076e873b..09e1cae9ec00ab 100644 --- a/app/javascript/images/app-icon.svg +++ b/app/javascript/images/app-icon.svg @@ -1,28 +1 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - +Logomark_DIGITAL_Red_500X500 \ No newline at end of file diff --git a/app/javascript/images/logo-symbol-icon.svg b/app/javascript/images/logo-symbol-icon.svg index c4c14f098afa02..09e1cae9ec00ab 100644 --- a/app/javascript/images/logo-symbol-icon.svg +++ b/app/javascript/images/logo-symbol-icon.svg @@ -1,2 +1 @@ - - +Logomark_DIGITAL_Red_500X500 \ No newline at end of file diff --git a/app/javascript/images/logo-symbol-wordmark.svg b/app/javascript/images/logo-symbol-wordmark.svg index ee0b636d936fa3..98833d696623b7 100644 --- a/app/javascript/images/logo-symbol-wordmark.svg +++ b/app/javascript/images/logo-symbol-wordmark.svg @@ -1,11 +1 @@ - - - - - - - - - - - +Vertical-Lockup_DIGITAL_Red_500px diff --git a/app/javascript/images/logo.svg b/app/javascript/images/logo.svg index 11d0c30c56271b..09e1cae9ec00ab 100644 --- a/app/javascript/images/logo.svg +++ b/app/javascript/images/logo.svg @@ -1,10 +1 @@ - - - - - - - - - - +Logomark_DIGITAL_Red_500X500 \ No newline at end of file diff --git a/app/javascript/images/mailer/logo.png b/app/javascript/images/mailer/logo.png index 784be9539f3474..89b030a691a337 100644 Binary files a/app/javascript/images/mailer/logo.png and b/app/javascript/images/mailer/logo.png differ diff --git a/app/javascript/images/mailer/wordmark.png b/app/javascript/images/mailer/wordmark.png index 6772b3318dc35c..2a0ca522f2d596 100644 Binary files a/app/javascript/images/mailer/wordmark.png and b/app/javascript/images/mailer/wordmark.png differ diff --git a/app/javascript/images/preview.png b/app/javascript/images/preview.png index 3d3a17b23c5591..9e247425f264f4 100644 Binary files a/app/javascript/images/preview.png and b/app/javascript/images/preview.png differ diff --git a/app/javascript/mastodon/features/compose/components/compose_form.jsx b/app/javascript/mastodon/features/compose/components/compose_form.jsx index 9222b2dc87703b..962310a284a6bc 100644 --- a/app/javascript/mastodon/features/compose/components/compose_form.jsx +++ b/app/javascript/mastodon/features/compose/components/compose_form.jsx @@ -100,7 +100,7 @@ class ComposeForm extends ImmutablePureComponent { const fulltext = this.getFulltextForCharacterCounting(); const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0; - return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia)); + return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 5000 || (isOnlyWhitespace && !anyMedia)); }; handleSubmit = (e) => { @@ -297,7 +297,7 @@ class ComposeForm extends ImmutablePureComponent {
- +
diff --git a/app/javascript/mastodon/features/compose/components/poll_form.jsx b/app/javascript/mastodon/features/compose/components/poll_form.jsx index 1a4d30abe71393..394faeae2e1b01 100644 --- a/app/javascript/mastodon/features/compose/components/poll_form.jsx +++ b/app/javascript/mastodon/features/compose/components/poll_form.jsx @@ -164,7 +164,7 @@ class PollForm extends ImmutablePureComponent {
- + {/* eslint-disable-next-line jsx-a11y/no-onchange */}