From 4e65af7b71e5058c971d1cf339476fea4737c5c5 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Fri, 19 May 2023 20:48:11 -0700 Subject: [PATCH 01/17] vagrantfile fixes and backwards compat with alt text chars --- .env.vagrant | 2 ++ Vagrantfile | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.env.vagrant b/.env.vagrant index 32ed9b92294bb5..f593b35a423302 100644 --- a/.env.vagrant +++ b/.env.vagrant @@ -2,3 +2,5 @@ VAGRANT=true LOCAL_DOMAIN=mastodon.local BIND=0.0.0.0 DB_HOST=/var/run/postgresql/ +MAX_ALT_TEXT_CHARS=1000000 +MAX_TOOT_CHARS=1000000 diff --git a/Vagrantfile b/Vagrantfile index 043bab3e9158e7..c5942dedeaac4f 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -84,7 +84,7 @@ yarn set version classic yarn install # Build Mastodon -export RAILS_ENV=development +export RAILS_ENV=development export $(cat ".env.vagrant" | xargs) bundle exec rails db:setup @@ -132,7 +132,7 @@ Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| end if config.vm.networks.any? { |type, options| type == :private_network } - config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'actimeo=1'] + config.vm.synced_folder ".", "/vagrant", type: "nfs", mount_options: ['rw', 'vers=3', 'tcp', 'actimeo=1'] else config.vm.synced_folder ".", "/vagrant" end From f2525457df9a12f2d42328d115d2e5da472bed67 Mon Sep 17 00:00:00 2001 From: hobgoblina <20880695+hobgoblina@users.noreply.github.com> Date: Sun, 21 Jul 2024 00:16:51 +0000 Subject: [PATCH 02/17] Update robots.txt --- public/robots.txt | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/public/robots.txt b/public/robots.txt index f8bbfa4c9f707d..39c9657a8b674a 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -104,6 +104,18 @@ Disallow: / User-agent: GPTBot Disallow: / +# AI Data Scraper +# https://darkvisitors.com/agents/meta-externalagent + +User-agent: Meta-ExternalAgent +Disallow: / + +# AI Assistant +# https://darkvisitors.com/agents/meta-externalfetcher + +User-agent: Meta-ExternalFetcher +Disallow: / + # AI Data Scraper # https://darkvisitors.com/agents/omgili @@ -116,6 +128,12 @@ Disallow: / User-agent: PerplexityBot Disallow: / +# AI Data Scraper +# https://darkvisitors.com/agents/timpibot + +User-agent: Timpibot +Disallow: / + # AI Search Crawler # https://darkvisitors.com/agents/youbot From 14a545dab577fe2cb29052adfb4e75d22eec7b0d Mon Sep 17 00:00:00 2001 From: hobgoblina <20880695+hobgoblina@users.noreply.github.com> Date: Sun, 4 Aug 2024 00:16:49 +0000 Subject: [PATCH 03/17] Update robots.txt --- public/robots.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/public/robots.txt b/public/robots.txt index 39c9657a8b674a..5e726910270577 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -116,6 +116,12 @@ Disallow: / User-agent: Meta-ExternalFetcher Disallow: / +# AI Search Crawler +# https://darkvisitors.com/agents/oai-searchbot + +User-agent: OAI-SearchBot +Disallow: / + # AI Data Scraper # https://darkvisitors.com/agents/omgili From 1f11423c08c8a3eefb2ec821e4e6101e3aab909d Mon Sep 17 00:00:00 2001 From: hobgoblina <20880695+hobgoblina@users.noreply.github.com> Date: Sun, 25 Aug 2024 00:17:10 +0000 Subject: [PATCH 04/17] Update robots.txt --- public/robots.txt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/public/robots.txt b/public/robots.txt index 5e726910270577..26ccaa30000069 100644 --- a/public/robots.txt +++ b/public/robots.txt @@ -140,6 +140,12 @@ Disallow: / User-agent: Timpibot Disallow: / +# AI Data Scraper +# https://darkvisitors.com/agents/webzio-extended + +User-agent: Webzio-Extended +Disallow: / + # AI Search Crawler # https://darkvisitors.com/agents/youbot From 24d2caf11e20dca8b6612a2febc1317d3013af77 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Wed, 28 Aug 2024 01:50:18 -0700 Subject: [PATCH 05/17] wait, actually we want it to just be a column on the account, because it's loaded on public, not when logged in. damn it. checkpointing so i can return here if needed --- app/javascript/flavours/glitch/initial_state.js | 4 ++++ .../flavours/glitch/styles/neuromatchstodon/index.scss | 1 + .../glitch/styles/neuromatchstodon/myspace.scss | 3 +++ app/models/concerns/user/has_settings.rb | 4 ++++ app/models/user_settings.rb | 4 ++++ app/views/accounts/show.html.haml | 3 +++ .../settings/preferences/appearance/show.html.haml | 5 +++++ config/initializers/simple_form.rb | 10 ++++++++++ config/locales/en.yml | 1 + config/locales/simple_form.en.yml | 3 +++ 10 files changed, 38 insertions(+) create mode 100644 app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index c5628f51ce475c..47679a88ff7850 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -49,6 +49,7 @@ * @property {string} status_page_url * @property {boolean} system_emoji_font * @property {string} default_content_type + * @property {string} account_css */ /** @@ -145,6 +146,9 @@ export const pollLimits = (initialState && initialState.poll_limits); export const defaultContentType = getMeta('default_content_type'); export const useSystemEmojiFont = getMeta('system_emoji_font'); +// Neuromatchstodon-specific settings +export const accountCSS = getMeta('account_css'); + /** * @returns {string | undefined} */ diff --git a/app/javascript/flavours/glitch/styles/neuromatchstodon/index.scss b/app/javascript/flavours/glitch/styles/neuromatchstodon/index.scss index 9c3885ff72ad8f..ee9c375fc20f0f 100644 --- a/app/javascript/flavours/glitch/styles/neuromatchstodon/index.scss +++ b/app/javascript/flavours/glitch/styles/neuromatchstodon/index.scss @@ -1,3 +1,4 @@ @import 'latex'; @import 'bigger_collapsed_statuses'; @import 'better_code_blocks'; +@import 'myspace'; diff --git a/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss new file mode 100644 index 00000000000000..f09b7421a411b4 --- /dev/null +++ b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss @@ -0,0 +1,3 @@ +#user_settings_attributes_neuromatchstodon\.account_css { + font-family: $font-monospace; +} diff --git a/app/models/concerns/user/has_settings.rb b/app/models/concerns/user/has_settings.rb index b79726e38aedf6..47148278da7a5e 100644 --- a/app/models/concerns/user/has_settings.rb +++ b/app/models/concerns/user/has_settings.rb @@ -123,6 +123,10 @@ def setting_hide_followers_count settings['hide_followers_count'] end + def setting_account_css + settings['neuromatchstodon.account_css'] + end + def allows_report_emails? settings['notification_emails.report'] end diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb index 3b245a4e461941..618799037d6b8f 100644 --- a/app/models/user_settings.rb +++ b/app/models/user_settings.rb @@ -61,6 +61,10 @@ class KeyError < Error; end setting :must_be_following_dm, default: false end + namespace :neuromatchstodon do + setting :account_css, default: nil + end + def initialize(original_hash) @original_hash = original_hash || {} end diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index dde9c508474901..f149a39364ee9d 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -11,6 +11,9 @@ - @account.fields.select(&:verifiable?).each do |field| %link{ rel: 'me', type: 'text/html', href: field.value }/ + -# - if @account.user_setting_account_css? + %meta{ name: 'account_css', content: @account.user_setting_account_css } + = opengraph 'og:type', 'profile' = render 'og', account: @account, url: short_account_url(@account, only_path: false) diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index b0cd1cba09d63c..43d346fa33cb12 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -86,5 +86,10 @@ .fields-group = ff.input :'web.expand_content_warnings', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_expand_spoilers') + %h4= t 'appearance.myspace_mode' + + .fields-group + = ff.input :'neuromatchstodon.account_css', as: :text, wrapper: :with_block_label, label: I18n.t('simple_form.labels.defaults.setting_myspace_account_css'), hint: I18n.t('simple_form.hints.defaults.setting_myspace_account_css'), neuromatchstodon_only: true + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/initializers/simple_form.rb b/config/initializers/simple_form.rb index 2fd87acc8aca64..fc7fc21999ce0d 100644 --- a/config/initializers/simple_form.rb +++ b/config/initializers/simple_form.rb @@ -38,10 +38,20 @@ def glitch_only(_wrapper_options = nil) end end +module NeuromatchstodonOnlyComponent + def neuromatchstodon_only(_wrapper_options = nil) + return unless options[:neuromatchstodon_only] + + options[:label_text] = ->(raw_label_text, _required_label_text, _label_present) { safe_join([raw_label_text, ' ', content_tag(:span, I18n.t('simple_form.neuromatchstodon_only'), class: 'glitch_only')]) } + nil + end +end + SimpleForm.include_component(AppendComponent) SimpleForm.include_component(RecommendedComponent) SimpleForm.include_component(WarningHintComponent) SimpleForm.include_component(GlitchOnlyComponent) +SimpleForm.include_component(NeuromatchstodonOnlyComponent) SimpleForm.setup do |config| # Wrappers are used by the form builder to generate a diff --git a/config/locales/en.yml b/config/locales/en.yml index 1df9af88d95306..3d18620fbd466c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1060,6 +1060,7 @@ en: guide_link: https://crowdin.com/project/mastodon guide_link_text: Everyone can contribute. sensitive_content: Sensitive content + myspace_mode: "MySpace Mode" application_mailer: notification_preferences: Change email preferences salutation: "%{name}," diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index fee3a6151ad419..07bf9b7fc05e4d 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -63,6 +63,7 @@ en: setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed username: You can use letters, numbers, and underscores whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word + setting_myspace_account_css: Custom CSS that is applied to your account page domain_allow: domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored email_domain_block: @@ -233,6 +234,7 @@ en: username: Username username_or_email: Username or Email whole_word: Whole word + setting_myspace_account_css: Account CSS email_domain_block: with_dns_records: Include MX records and IPs of the domain featured_tag: @@ -339,3 +341,4 @@ en: sessions: webauthn: Use one of your security keys to sign in 'yes': 'Yes' + neuromatchstodon_only: "Neuromatchstodon Only" From b0c06fcaf9e950fc1f6d8215b834047a385f874f Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Wed, 28 Aug 2024 02:32:05 -0700 Subject: [PATCH 06/17] working myspace mode --- .../settings/profiles_controller.rb | 2 +- .../flavours/glitch/initial_state.js | 4 ---- .../styles/neuromatchstodon/myspace.scss | 2 +- app/models/account.rb | 3 ++- app/models/concerns/user/has_settings.rb | 4 ---- app/models/user_settings.rb | 4 ---- app/views/accounts/show.html.haml | 5 +++-- .../preferences/appearance/show.html.haml | 5 ----- app/views/settings/profiles/show.html.haml | 5 +++++ config/locales/en.yml | 2 +- config/locales/simple_form.en.yml | 4 ++-- ...240828084252_add_account_css_to_account.rb | 7 +++++++ db/schema.rb | 21 ++++++++++--------- 13 files changed, 33 insertions(+), 35 deletions(-) create mode 100644 db/migrate/20240828084252_add_account_css_to_account.rb diff --git a/app/controllers/settings/profiles_controller.rb b/app/controllers/settings/profiles_controller.rb index 8ae69b7fe066d1..8da323f2786991 100644 --- a/app/controllers/settings/profiles_controller.rb +++ b/app/controllers/settings/profiles_controller.rb @@ -20,7 +20,7 @@ def update private def account_params - params.require(:account).permit(:display_name, :note, :avatar, :header, :bot, fields_attributes: [:name, :value]) + params.require(:account).permit(:display_name, :note, :avatar, :header, :bot, :account_css, fields_attributes: [:name, :value]) end def set_account diff --git a/app/javascript/flavours/glitch/initial_state.js b/app/javascript/flavours/glitch/initial_state.js index 47679a88ff7850..c5628f51ce475c 100644 --- a/app/javascript/flavours/glitch/initial_state.js +++ b/app/javascript/flavours/glitch/initial_state.js @@ -49,7 +49,6 @@ * @property {string} status_page_url * @property {boolean} system_emoji_font * @property {string} default_content_type - * @property {string} account_css */ /** @@ -146,9 +145,6 @@ export const pollLimits = (initialState && initialState.poll_limits); export const defaultContentType = getMeta('default_content_type'); export const useSystemEmojiFont = getMeta('system_emoji_font'); -// Neuromatchstodon-specific settings -export const accountCSS = getMeta('account_css'); - /** * @returns {string | undefined} */ diff --git a/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss index f09b7421a411b4..62b2b1c4dc42b9 100644 --- a/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss +++ b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss @@ -1,3 +1,3 @@ -#user_settings_attributes_neuromatchstodon\.account_css { +#account_account_css { font-family: $font-monospace; } diff --git a/app/models/account.rb b/app/models/account.rb index c344a30bbe98b9..63845221c828f8 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -45,12 +45,13 @@ # avatar_storage_schema_version :integer # header_storage_schema_version :integer # devices_url :string -# suspension_origin :integer # sensitized_at :datetime +# suspension_origin :integer # trendable :boolean # reviewed_at :datetime # requested_review_at :datetime # indexable :boolean default(FALSE), not null +# account_css :text # class Account < ApplicationRecord diff --git a/app/models/concerns/user/has_settings.rb b/app/models/concerns/user/has_settings.rb index 47148278da7a5e..b79726e38aedf6 100644 --- a/app/models/concerns/user/has_settings.rb +++ b/app/models/concerns/user/has_settings.rb @@ -123,10 +123,6 @@ def setting_hide_followers_count settings['hide_followers_count'] end - def setting_account_css - settings['neuromatchstodon.account_css'] - end - def allows_report_emails? settings['notification_emails.report'] end diff --git a/app/models/user_settings.rb b/app/models/user_settings.rb index 618799037d6b8f..3b245a4e461941 100644 --- a/app/models/user_settings.rb +++ b/app/models/user_settings.rb @@ -61,10 +61,6 @@ class KeyError < Error; end setting :must_be_following_dm, default: false end - namespace :neuromatchstodon do - setting :account_css, default: nil - end - def initialize(original_hash) @original_hash = original_hash || {} end diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index f149a39364ee9d..d7ca2037e776ef 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -11,8 +11,9 @@ - @account.fields.select(&:verifiable?).each do |field| %link{ rel: 'me', type: 'text/html', href: field.value }/ - -# - if @account.user_setting_account_css? - %meta{ name: 'account_css', content: @account.user_setting_account_css } + - if @account.account_css? + %style{ nonce: request.content_security_policy_nonce } + = @account.account_css = opengraph 'og:type', 'profile' = render 'og', account: @account, url: short_account_url(@account, only_path: false) diff --git a/app/views/settings/preferences/appearance/show.html.haml b/app/views/settings/preferences/appearance/show.html.haml index 43d346fa33cb12..b0cd1cba09d63c 100644 --- a/app/views/settings/preferences/appearance/show.html.haml +++ b/app/views/settings/preferences/appearance/show.html.haml @@ -86,10 +86,5 @@ .fields-group = ff.input :'web.expand_content_warnings', wrapper: :with_label, label: I18n.t('simple_form.labels.defaults.setting_expand_spoilers') - %h4= t 'appearance.myspace_mode' - - .fields-group - = ff.input :'neuromatchstodon.account_css', as: :text, wrapper: :with_block_label, label: I18n.t('simple_form.labels.defaults.setting_myspace_account_css'), hint: I18n.t('simple_form.hints.defaults.setting_myspace_account_css'), neuromatchstodon_only: true - .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/app/views/settings/profiles/show.html.haml b/app/views/settings/profiles/show.html.haml index 61ba79c4491f02..fc44f01402e1d1 100644 --- a/app/views/settings/profiles/show.html.haml +++ b/app/views/settings/profiles/show.html.haml @@ -67,5 +67,10 @@ .fields-group = f.input :bot, as: :boolean, wrapper: :with_label, hint: t('simple_form.hints.defaults.bot') + %h4= t 'edit_profile.myspace_mode' + + .fields-group + = f.input :account_css, as: :text, wrapper: :with_block_label, label: I18n.t('simple_form.labels.account.account_css'), hint: I18n.t('simple_form.hints.account.account_css'), neuromatchstodon_only: true + .actions = f.button :button, t('generic.save_changes'), type: :submit diff --git a/config/locales/en.yml b/config/locales/en.yml index 3d18620fbd466c..dccc71a8b65e9c 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1060,7 +1060,6 @@ en: guide_link: https://crowdin.com/project/mastodon guide_link_text: Everyone can contribute. sensitive_content: Sensitive content - myspace_mode: "MySpace Mode" application_mailer: notification_preferences: Change email preferences salutation: "%{name}," @@ -1237,6 +1236,7 @@ en: basic_information: Basic information hint_html: "Customize what people see on your public profile and next to your posts. Other people are more likely to follow you back and interact with you when you have a filled out profile and a profile picture." other: Other + myspace_mode: "MySpace Mode" errors: '400': The request you submitted was invalid or malformed. '403': You don't have permission to view this page. diff --git a/config/locales/simple_form.en.yml b/config/locales/simple_form.en.yml index 07bf9b7fc05e4d..9300b0f862d076 100644 --- a/config/locales/simple_form.en.yml +++ b/config/locales/simple_form.en.yml @@ -10,6 +10,7 @@ en: note: 'You can @mention other people or #hashtags.' show_collections: People will be able to browse through your follows and followers. People that you follow will see that you follow them regardless. unlocked: People will be able to follow you without requesting approval. Uncheck if you want to review follow requests and chose whether to accept or reject new followers. + account_css: Custom CSS that is applied to your account page account_alias: acct: Specify the username@domain of the account you want to move from account_migration: @@ -63,7 +64,6 @@ en: setting_use_pending_items: Hide timeline updates behind a click instead of automatically scrolling the feed username: You can use letters, numbers, and underscores whole_word: When the keyword or phrase is alphanumeric only, it will only be applied if it matches the whole word - setting_myspace_account_css: Custom CSS that is applied to your account page domain_allow: domain: This domain will be able to fetch data from this server and incoming data from it will be processed and stored email_domain_block: @@ -151,6 +151,7 @@ en: indexable: Include public posts in search results show_collections: Show follows and followers on profile unlocked: Automatically accept new followers + account_css: Account CSS account_alias: acct: Handle of the old account account_migration: @@ -234,7 +235,6 @@ en: username: Username username_or_email: Username or Email whole_word: Whole word - setting_myspace_account_css: Account CSS email_domain_block: with_dns_records: Include MX records and IPs of the domain featured_tag: diff --git a/db/migrate/20240828084252_add_account_css_to_account.rb b/db/migrate/20240828084252_add_account_css_to_account.rb new file mode 100644 index 00000000000000..01a14f31f37a37 --- /dev/null +++ b/db/migrate/20240828084252_add_account_css_to_account.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddAccountCssToAccount < ActiveRecord::Migration[7.1] + def change + add_column :accounts, :account_css, :text, null: true + end +end diff --git a/db/schema.rb b/db/schema.rb index a3afab78167fe8..5ac44d4d653c3f 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2024_08_08_125420) do +ActiveRecord::Schema[7.1].define(version: 2024_08_28_084252) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -200,6 +200,7 @@ t.datetime "reviewed_at", precision: nil t.datetime "requested_review_at", precision: nil t.boolean "indexable", default: false, null: false + t.text "account_css" t.index "(((setweight(to_tsvector('simple'::regconfig, (display_name)::text), 'A'::\"char\") || setweight(to_tsvector('simple'::regconfig, (username)::text), 'B'::\"char\")) || setweight(to_tsvector('simple'::regconfig, (COALESCE(domain, ''::character varying))::text), 'C'::\"char\")))", name: "search_index", using: :gin t.index "lower((username)::text), COALESCE(lower((domain)::text), ''::text)", name: "index_accounts_on_username_and_domain_lower", unique: true t.index ["domain", "id"], name: "index_accounts_on_domain_and_id" @@ -1428,9 +1429,9 @@ add_index "instances", ["domain"], name: "index_instances_on_domain", unique: true create_view "user_ips", sql_definition: <<-SQL - SELECT user_id, - ip, - max(used_at) AS used_at + SELECT t0.user_id, + t0.ip, + max(t0.used_at) AS used_at FROM ( SELECT users.id AS user_id, users.sign_up_ip AS ip, users.created_at AS used_at @@ -1447,7 +1448,7 @@ login_activities.created_at FROM login_activities WHERE (login_activities.success = true)) t0 - GROUP BY user_id, ip; + GROUP BY t0.user_id, t0.ip; SQL create_view "account_summaries", materialized: true, sql_definition: <<-SQL SELECT accounts.id AS account_id, @@ -1468,9 +1469,9 @@ add_index "account_summaries", ["account_id"], name: "index_account_summaries_on_account_id", unique: true create_view "global_follow_recommendations", materialized: true, sql_definition: <<-SQL - SELECT account_id, - sum(rank) AS rank, - array_agg(reason) AS reason + SELECT t0.account_id, + sum(t0.rank) AS rank, + array_agg(t0.reason) AS reason FROM ( SELECT account_summaries.account_id, ((count(follows.id))::numeric / (1.0 + (count(follows.id))::numeric)) AS rank, 'most_followed'::text AS reason @@ -1494,8 +1495,8 @@ WHERE (follow_recommendation_suppressions.account_id = statuses.account_id))))) GROUP BY account_summaries.account_id HAVING (sum((status_stats.reblogs_count + status_stats.favourites_count)) >= (5)::numeric)) t0 - GROUP BY account_id - ORDER BY (sum(rank)) DESC; + GROUP BY t0.account_id + ORDER BY (sum(t0.rank)) DESC; SQL add_index "global_follow_recommendations", ["account_id"], name: "index_global_follow_recommendations_on_account_id", unique: true From 967714dd94c6f489da1962d73da77b5a1761f941 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Wed, 28 Aug 2024 04:25:05 -0700 Subject: [PATCH 07/17] sanitize CSS --- app/models/account.rb | 1 + .../settings/profiles_controller_spec.rb | 27 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/app/models/account.rb b/app/models/account.rb index 63845221c828f8..f07cecb4600fa4 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -115,6 +115,7 @@ class Account < ApplicationRecord validates :followers_url, absence: true, if: :local?, on: :create normalizes :username, with: ->(username) { username.squish } + normalizes :account_css, with: ->(account_css) { Sanitize::CSS.stylesheet(account_css, Sanitize::Config::RELAXED) } scope :without_internal, -> { where(id: 1...) } scope :remote, -> { where.not(domain: nil) } diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb index e3197f0a6d7882..83e4973d8a1cf3 100644 --- a/spec/controllers/settings/profiles_controller_spec.rb +++ b/spec/controllers/settings/profiles_controller_spec.rb @@ -48,4 +48,31 @@ expect(ActivityPub::UpdateDistributionWorker).to have_received(:perform_async).with(account.id) end end + + describe 'PUT #account_css with custom css' do + it 'hopefully removes malicious css' do + put :update, params: { + account: { + account_css: <<~CSS, + @import url(swear_words.css); + a { text-decoration: none; } + + a:hover { + left: expression(alert('xss!')); + text-decoration: underline; + } + CSS + }, + } + expect(account.reload.account_css).to eq <<~CSS + + a { text-decoration: none; } + + a:hover { + + text-decoration: underline; + } + CSS + end + end end From 033d0ab25eaa28f2a5e9100f276c2f9f02140435 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 21:01:38 -0700 Subject: [PATCH 08/17] fix string in test --- spec/controllers/settings/profiles_controller_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/controllers/settings/profiles_controller_spec.rb b/spec/controllers/settings/profiles_controller_spec.rb index 83e4973d8a1cf3..6450c95444c884 100644 --- a/spec/controllers/settings/profiles_controller_spec.rb +++ b/spec/controllers/settings/profiles_controller_spec.rb @@ -58,8 +58,8 @@ a { text-decoration: none; } a:hover { - left: expression(alert('xss!')); - text-decoration: underline; + left: expression(alert('xss!')); + text-decoration: underline; } CSS }, @@ -70,7 +70,7 @@ a:hover { - text-decoration: underline; + text-decoration: underline; } CSS end From 45fb596539472dc7c999eb3a4e30f87fa815664c Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 22:33:56 -0700 Subject: [PATCH 09/17] move account_css to account header component, fix css change on navigation --- .../flavours/glitch/api_types/accounts.ts | 1 + .../features/account/components/header.jsx | 9 ++++- .../flavours/glitch/models/account.ts | 39 ++++++++++++++++++- .../styles/neuromatchstodon/myspace.scss | 1 + app/serializers/rest/account_serializer.rb | 3 +- app/views/accounts/show.html.haml | 4 -- 6 files changed, 49 insertions(+), 8 deletions(-) diff --git a/app/javascript/flavours/glitch/api_types/accounts.ts b/app/javascript/flavours/glitch/api_types/accounts.ts index 5bf3e64288c76e..d6dada067b6678 100644 --- a/app/javascript/flavours/glitch/api_types/accounts.ts +++ b/app/javascript/flavours/glitch/api_types/accounts.ts @@ -44,4 +44,5 @@ export interface ApiAccountJSON { limited?: boolean; memorial?: boolean; hide_collections: boolean; + account_css?: string; } diff --git a/app/javascript/flavours/glitch/features/account/components/header.jsx b/app/javascript/flavours/glitch/features/account/components/header.jsx index 62c8c84c66eafa..d504ff260cf174 100644 --- a/app/javascript/flavours/glitch/features/account/components/header.jsx +++ b/app/javascript/flavours/glitch/features/account/components/header.jsx @@ -3,8 +3,8 @@ import PropTypes from 'prop-types'; import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; import classNames from 'classnames'; -import { Helmet } from 'react-helmet'; -import { withRouter } from 'react-router-dom'; +import {Helmet} from 'react-helmet'; +import {withRouter} from 'react-router-dom'; import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePureComponent from 'react-immutable-pure-component'; @@ -405,6 +405,11 @@ class Header extends ImmutablePureComponent { {titleFromAccount(account)} + {account.account_css && ( + + )} ); diff --git a/app/javascript/flavours/glitch/models/account.ts b/app/javascript/flavours/glitch/models/account.ts index 0b698ead3d1930..6ad2e779e53012 100644 --- a/app/javascript/flavours/glitch/models/account.ts +++ b/app/javascript/flavours/glitch/models/account.ts @@ -60,7 +60,43 @@ export interface AccountShape export type Account = RecordOf; -export const accountDefaultValues: AccountShape = { +export const accountDefaultValues: { + note: string; + hidden: boolean; + bot: boolean; + roles: Immutable.List; + moved: null; + indexable: boolean; + created_at: string; + header_static: string; + account_css: string; + hide_collections: boolean; + id: string; + memorial: boolean; + locked: boolean; + display_name_html: string; + group: boolean; + emojis: Immutable.List; + noindex: boolean; + limited: boolean; + avatar: string; + display_name: string; + note_plain: string; + uri: string; + url: string; + suspended: boolean; + following_count: number; + discoverable: boolean; + last_status_at: string; + statuses_count: number; + followers_count: number; + note_emojified: string; + header: string; + avatar_static: string; + fields: Immutable.List; + acct: string; + username: string; +} = { acct: '', avatar: '', avatar_static: '', @@ -95,6 +131,7 @@ export const accountDefaultValues: AccountShape = { limited: false, moved: null, hide_collections: false, + account_css: '', }; const AccountFactory = ImmutableRecord(accountDefaultValues); diff --git a/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss index 62b2b1c4dc42b9..7bcb775aa1a9b9 100644 --- a/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss +++ b/app/javascript/flavours/glitch/styles/neuromatchstodon/myspace.scss @@ -1,3 +1,4 @@ #account_account_css { font-family: $font-monospace; + height: 15em; } diff --git a/app/serializers/rest/account_serializer.rb b/app/serializers/rest/account_serializer.rb index a10d6988817370..dbaa15944b5e28 100644 --- a/app/serializers/rest/account_serializer.rb +++ b/app/serializers/rest/account_serializer.rb @@ -8,7 +8,8 @@ class REST::AccountSerializer < ActiveModel::Serializer attributes :id, :username, :acct, :display_name, :locked, :bot, :discoverable, :indexable, :group, :created_at, :note, :url, :uri, :avatar, :avatar_static, :header, :header_static, - :followers_count, :following_count, :statuses_count, :last_status_at, :hide_collections + :followers_count, :following_count, :statuses_count, :last_status_at, :hide_collections, + :account_css has_one :moved_to_account, key: :moved, serializer: REST::AccountSerializer, if: :moved_and_not_nested? diff --git a/app/views/accounts/show.html.haml b/app/views/accounts/show.html.haml index d7ca2037e776ef..dde9c508474901 100644 --- a/app/views/accounts/show.html.haml +++ b/app/views/accounts/show.html.haml @@ -11,10 +11,6 @@ - @account.fields.select(&:verifiable?).each do |field| %link{ rel: 'me', type: 'text/html', href: field.value }/ - - if @account.account_css? - %style{ nonce: request.content_security_policy_nonce } - = @account.account_css - = opengraph 'og:type', 'profile' = render 'og', account: @account, url: short_account_url(@account, only_path: false) From c91a72da16e66bc65d6a54ee802d7e43d5af7a28 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 22:38:21 -0700 Subject: [PATCH 10/17] attempt at tests, but cant run locally tso runnning on ci --- spec/support/stories/profile_stories.rb | 16 +++++++++++++++- spec/system/profile_spec.rb | 11 +++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb index 07eaaca9fb93b0..cad06a17e57426 100644 --- a/spec/support/stories/profile_stories.rb +++ b/spec/support/stories/profile_stories.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module ProfileStories - attr_reader :bob, :alice, :alice_bio + attr_reader :bob, :alice, :alice_bio, :chupacabra, :chupacabra_css def fill_in_auth_details(email, password) fill_in 'user_email', with: email @@ -43,6 +43,20 @@ def with_alice_as_local_user ) end + def with_chupacabras_fancy_profile + @chupacabra_css = <<~CSS + body { + background-color: red !important; + } + CSS + + @chupacabra = Fabricate( + :user, + email: 'chupacabra@example.com', password: password, confirmed_at: confirmed_at, + account: Fabricate(:account, username: 'chupacabra', note: 'I am gonna getcha!', account_css: @chupacabra_css) + ) + end + def confirmed_at @confirmed_at ||= Time.zone.now end diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 2517e823b50c5f..b3f7dc95dd070b 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -12,6 +12,7 @@ before do as_a_logged_in_user with_alice_as_local_user + with_chupacabras_fancy_profile end it 'I can view Annes public account' do @@ -30,4 +31,14 @@ expect(subject).to have_content 'Changes successfully saved!' end + + it 'Can have custom account_css set' do + visit account_path('chupacabra') + expect(subject).to include('background-color: red !important') + expect(subject).to have_xpath('//*[@id="account-css"]') + + visit account_path('alice') + expect(subject).to_not include('background-color: red !important') + expect(subject).to have_no_xpath('//*[@id="account-css"]') + end end From 0fb067e488595573c0d56fc974cf1b8e1a7a223f Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 22:40:36 -0700 Subject: [PATCH 11/17] use have_content instead --- spec/system/profile_spec.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index b3f7dc95dd070b..1cd3e62bc02f35 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -34,11 +34,11 @@ it 'Can have custom account_css set' do visit account_path('chupacabra') - expect(subject).to include('background-color: red !important') + expect(subject).to have_content('background-color: red !important') expect(subject).to have_xpath('//*[@id="account-css"]') visit account_path('alice') - expect(subject).to_not include('background-color: red !important') + expect(subject).to have_no_content('background-color: red !important') expect(subject).to have_no_xpath('//*[@id="account-css"]') end end From 7697073fa24753f426a11a156a6679fa1a2b984d Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 23:16:14 -0700 Subject: [PATCH 12/17] mark as requiring js --- spec/system/profile_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 1cd3e62bc02f35..82ddb07fb5a809 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -32,7 +32,7 @@ expect(subject).to have_content 'Changes successfully saved!' end - it 'Can have custom account_css set' do + it 'Can have custom account_css set', :js do visit account_path('chupacabra') expect(subject).to have_content('background-color: red !important') expect(subject).to have_xpath('//*[@id="account-css"]') From 9cbc519a698d8c0470ecdc63a20afb7d472f5e3a Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 31 Aug 2024 23:45:25 -0700 Subject: [PATCH 13/17] give alice da css becvause there's something wrong with making the account --- spec/support/stories/profile_stories.rb | 19 +++++-------------- spec/system/profile_spec.rb | 9 ++++----- 2 files changed, 9 insertions(+), 19 deletions(-) diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb index cad06a17e57426..c85e5e7da0eb69 100644 --- a/spec/support/stories/profile_stories.rb +++ b/spec/support/stories/profile_stories.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module ProfileStories - attr_reader :bob, :alice, :alice_bio, :chupacabra, :chupacabra_css + attr_reader :bob, :alice, :alice_bio, :alice_css def fill_in_auth_details(email, password) fill_in 'user_email', with: email @@ -35,25 +35,16 @@ def with_alice_as_local_user @alice_bio = '@alice and @bob are fictional characters commonly used as' \ 'placeholder names in #cryptology, as well as #science and' \ 'engineering 📖 literature. Not affiliated with @pepe.' - - @alice = Fabricate( - :user, - email: 'alice@example.com', password: password, confirmed_at: confirmed_at, - account: Fabricate(:account, username: 'alice', note: @alice_bio) - ) - end - - def with_chupacabras_fancy_profile - @chupacabra_css = <<~CSS + @alice_css = <<~CSS body { background-color: red !important; } CSS - @chupacabra = Fabricate( + @alice = Fabricate( :user, - email: 'chupacabra@example.com', password: password, confirmed_at: confirmed_at, - account: Fabricate(:account, username: 'chupacabra', note: 'I am gonna getcha!', account_css: @chupacabra_css) + email: 'alice@example.com', password: password, confirmed_at: confirmed_at, + account: Fabricate(:account, username: 'alice', note: @alice_bio, account_css: @alice_css) ) end diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 82ddb07fb5a809..123f68c7e43971 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -12,7 +12,6 @@ before do as_a_logged_in_user with_alice_as_local_user - with_chupacabras_fancy_profile end it 'I can view Annes public account' do @@ -33,12 +32,12 @@ end it 'Can have custom account_css set', :js do - visit account_path('chupacabra') - expect(subject).to have_content('background-color: red !important') + visit account_path('alice') + expect(subject.html).to have_content('background-color: red !important') expect(subject).to have_xpath('//*[@id="account-css"]') - visit account_path('alice') - expect(subject).to have_no_content('background-color: red !important') + visit account_path('bob') + expect(subject.html).to have_no_content('background-color: red !important') expect(subject).to have_no_xpath('//*[@id="account-css"]') end end From 1114eee5e904adbe1f961f046fc3b74dc8979784 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 14 Sep 2024 18:47:16 -0700 Subject: [PATCH 14/17] revert expanding AccountShape in ts --- .../flavours/glitch/models/account.ts | 38 +------------------ 1 file changed, 1 insertion(+), 37 deletions(-) diff --git a/app/javascript/flavours/glitch/models/account.ts b/app/javascript/flavours/glitch/models/account.ts index 6ad2e779e53012..eaad1fd3d9a9fb 100644 --- a/app/javascript/flavours/glitch/models/account.ts +++ b/app/javascript/flavours/glitch/models/account.ts @@ -60,43 +60,7 @@ export interface AccountShape export type Account = RecordOf; -export const accountDefaultValues: { - note: string; - hidden: boolean; - bot: boolean; - roles: Immutable.List; - moved: null; - indexable: boolean; - created_at: string; - header_static: string; - account_css: string; - hide_collections: boolean; - id: string; - memorial: boolean; - locked: boolean; - display_name_html: string; - group: boolean; - emojis: Immutable.List; - noindex: boolean; - limited: boolean; - avatar: string; - display_name: string; - note_plain: string; - uri: string; - url: string; - suspended: boolean; - following_count: number; - discoverable: boolean; - last_status_at: string; - statuses_count: number; - followers_count: number; - note_emojified: string; - header: string; - avatar_static: string; - fields: Immutable.List; - acct: string; - username: string; -} = { +export const accountDefaultValues: AccountShape = { acct: '', avatar: '', avatar_static: '', From a6e07a0bbd48399f0515005296517acad1fbd98e Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 14 Sep 2024 19:15:13 -0700 Subject: [PATCH 15/17] split end to end tests in profile to separate describe block --- spec/system/profile_spec.rb | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 123f68c7e43971..85a59a71be0249 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -31,13 +31,20 @@ expect(subject).to have_content 'Changes successfully saved!' end - it 'Can have custom account_css set', :js do - visit account_path('alice') - expect(subject.html).to have_content('background-color: red !important') - expect(subject).to have_xpath('//*[@id="account-css"]') - - visit account_path('bob') - expect(subject.html).to have_no_content('background-color: red !important') - expect(subject).to have_no_xpath('//*[@id="account-css"]') + describe 'with JS', :js do + before do + as_a_logged_in_user + with_alice_as_local_user + end + + it 'Can have custom account_css set' do + visit account_path('alice') + expect(subject.html).to have_content('background-color: red !important') + expect(subject).to have_xpath('//*[@id="account-css"]') + + visit account_path('bob') + expect(subject.html).to have_no_content('background-color: red !important') + expect(subject).to have_no_xpath('//*[@id="account-css"]') + end end end From 323748b9cc6760b86f95780aecb3485c12d0a29a Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sat, 14 Sep 2024 19:32:03 -0700 Subject: [PATCH 16/17] restore fancy profile to non-alice profile where it belongs --- spec/support/stories/profile_stories.rb | 19 ++++++++++++++----- spec/system/profile_spec.rb | 5 ++--- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb index c85e5e7da0eb69..cad06a17e57426 100644 --- a/spec/support/stories/profile_stories.rb +++ b/spec/support/stories/profile_stories.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true module ProfileStories - attr_reader :bob, :alice, :alice_bio, :alice_css + attr_reader :bob, :alice, :alice_bio, :chupacabra, :chupacabra_css def fill_in_auth_details(email, password) fill_in 'user_email', with: email @@ -35,16 +35,25 @@ def with_alice_as_local_user @alice_bio = '@alice and @bob are fictional characters commonly used as' \ 'placeholder names in #cryptology, as well as #science and' \ 'engineering 📖 literature. Not affiliated with @pepe.' - @alice_css = <<~CSS + + @alice = Fabricate( + :user, + email: 'alice@example.com', password: password, confirmed_at: confirmed_at, + account: Fabricate(:account, username: 'alice', note: @alice_bio) + ) + end + + def with_chupacabras_fancy_profile + @chupacabra_css = <<~CSS body { background-color: red !important; } CSS - @alice = Fabricate( + @chupacabra = Fabricate( :user, - email: 'alice@example.com', password: password, confirmed_at: confirmed_at, - account: Fabricate(:account, username: 'alice', note: @alice_bio, account_css: @alice_css) + email: 'chupacabra@example.com', password: password, confirmed_at: confirmed_at, + account: Fabricate(:account, username: 'chupacabra', note: 'I am gonna getcha!', account_css: @chupacabra_css) ) end diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index 85a59a71be0249..b7763f219101a8 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -33,12 +33,11 @@ describe 'with JS', :js do before do - as_a_logged_in_user - with_alice_as_local_user + with_chupacabras_fancy_profile end it 'Can have custom account_css set' do - visit account_path('alice') + visit account_path('chupacabra') expect(subject.html).to have_content('background-color: red !important') expect(subject).to have_xpath('//*[@id="account-css"]') From f11b82e6a8223f7fe6e6c7b7d7cf808909ffd434 Mon Sep 17 00:00:00 2001 From: sneakers-the-rat Date: Sun, 22 Sep 2024 16:04:12 -0700 Subject: [PATCH 17/17] finish onboarding, wait for page to load --- spec/support/stories/profile_stories.rb | 1 + spec/system/profile_spec.rb | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/spec/support/stories/profile_stories.rb b/spec/support/stories/profile_stories.rb index cad06a17e57426..45c02875a28aab 100644 --- a/spec/support/stories/profile_stories.rb +++ b/spec/support/stories/profile_stories.rb @@ -55,6 +55,7 @@ def with_chupacabras_fancy_profile email: 'chupacabra@example.com', password: password, confirmed_at: confirmed_at, account: Fabricate(:account, username: 'chupacabra', note: 'I am gonna getcha!', account_css: @chupacabra_css) ) + Web::Setting.where(user: chupacabra).first_or_initialize(user: chupacabra).update!(data: { introductionVersion: 2018_12_16_044202 }) end def confirmed_at diff --git a/spec/system/profile_spec.rb b/spec/system/profile_spec.rb index b7763f219101a8..cb8e74285ed868 100644 --- a/spec/system/profile_spec.rb +++ b/spec/system/profile_spec.rb @@ -31,19 +31,20 @@ expect(subject).to have_content 'Changes successfully saved!' end - describe 'with JS', :js do + describe 'with JS', :js, :streaming do before do with_chupacabras_fancy_profile end it 'Can have custom account_css set' do visit account_path('chupacabra') + # wait for page to load... + page.find '.account__header' expect(subject.html).to have_content('background-color: red !important') - expect(subject).to have_xpath('//*[@id="account-css"]') visit account_path('bob') + page.find '.account__header' expect(subject.html).to have_no_content('background-color: red !important') - expect(subject).to have_no_xpath('//*[@id="account-css"]') end end end