Compare commits

...
This repository has been archived on 2023-03-18. You can view files and clone it, but cannot push or open issues or pull requests.

887 Commits

Author SHA1 Message Date
Penar Musaraj
c8381edf0c
Update Rails to v6.1.7.1 2023-01-23 20:32:19 -05:00
Penar Musaraj
c4ad6659dc
Revert "Update Rails to v6.1.7.1"
This reverts commit d45d9a31ac.
2023-01-23 20:31:38 -05:00
Penar Musaraj
d45d9a31ac
Update Rails to v6.1.7.1 2023-01-23 20:28:19 -05:00
Alan Guo Xiang Tan
df6d323bd1 Version bump to v2.8.14 (#19755) 2023-01-05 10:54:47 +08:00
Alan Guo Xiang Tan
ffc59a3b28 SECURITY: BCC active user emails from group SMTP (#19724)
When sending emails out via group SMTP, if we
are sending them to non-staged users we want
to mask those emails with BCC, just so we don't
expose them to anyone we shouldn't. Staged users
are ones that have likely only interacted with
support via email, and will likely include other
people who were CC'd on the original email to the
group.

Co-authored-by: Martin Brennan <martin@discourse.org>
2023-01-05 10:54:47 +08:00
Alan Guo Xiang Tan
7a47c7b3f1 Revert "SECURITY: BCC active user emails from group SMTP (#19724)"
This reverts commit a09dc2d5c2.
2023-01-05 10:54:47 +08:00
Alan Guo Xiang Tan
2bb31f1ce6 Revert "Version bump to v2.8.14 (#19755)"
This reverts commit 8665f06f63.
2023-01-05 10:54:47 +08:00
Alan Guo Xiang Tan
8665f06f63
Version bump to v2.8.14 (#19755) 2023-01-05 09:56:13 +08:00
Alan Guo Xiang Tan
a09dc2d5c2 SECURITY: BCC active user emails from group SMTP (#19724)
When sending emails out via group SMTP, if we
are sending them to non-staged users we want
to mask those emails with BCC, just so we don't
expose them to anyone we shouldn't. Staged users
are ones that have likely only interacted with
support via email, and will likely include other
people who were CC'd on the original email to the
group.

Co-authored-by: Martin Brennan <martin@discourse.org>
2023-01-05 09:45:30 +08:00
Alan Guo Xiang Tan
1cb5200450 Revert "SECURITY: BCC active user emails from group SMTP (#19724)"
This reverts commit 7bd83ef6b5.
2023-01-05 09:45:30 +08:00
Alan Guo Xiang Tan
c83a7c91d1
SECURITY: Convert send_digest to a post request (#19748)
Co-authored-by: Isaac Janzen <isaac.janzen@discourse.org>
2023-01-05 08:51:39 +08:00
Alan Guo Xiang Tan
fae0cd9f54
SECURITY: use rstrip instead of regex gsub to prevent ReDOS (#19738)
`rstrip` implementation is much more performant than regex

Co-authored-by: Krzysztof Kotlarek <kotlarek.krzysztof@gmail.com>
2023-01-05 08:51:33 +08:00
Alan Guo Xiang Tan
4bf306f0e3
SECURITY: Delete email tokens when a user's email is changed or deleted (#19736)
Co-authored-by: OsamaSayegh <asooomaasoooma90@gmail.com>
2023-01-05 08:51:27 +08:00
Alan Guo Xiang Tan
b9e2e997f4
SECURITY: Check the length of raw post body (#19734)
Co-authored-by: Jarek Radosz <jradosz@gmail.com>
2023-01-05 08:51:21 +08:00
Alan Guo Xiang Tan
66ab2d71ff
SECURITY: escape quotes in tag description when rendering (#19731)
Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
2023-01-05 08:51:16 +08:00
Alan Guo Xiang Tan
9470ae7190
SECURITY: Don't expose user post counts to users who can't see the topic (#19729)
Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
Co-authored-by: Penar Musaraj <pmusaraj@gmail.com>
2023-01-05 08:51:10 +08:00
Alan Guo Xiang Tan
06a70d249b
SECURITY: Sanitize PendingPost titles before rendering to prevent XSS (#19727)
Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
2023-01-05 08:51:00 +08:00
Alan Guo Xiang Tan
7bd83ef6b5
SECURITY: BCC active user emails from group SMTP (#19724)
When sending emails out via group SMTP, if we
are sending them to non-staged users we want
to mask those emails with BCC, just so we don't
expose them to anyone we shouldn't. Staged users
are ones that have likely only interacted with
support via email, and will likely include other
people who were CC'd on the original email to the
group.

Co-authored-by: Martin Brennan <martin@discourse.org>
2023-01-05 08:50:54 +08:00
David Taylor
c77a9f18be
DEV: Use ruby-2.7 for stable branch CI (#19749) 2023-01-05 08:50:22 +08:00
Selase Krakani
fbd6c300d2
SECURITY: Restrict unlisted topic creation (#19258) 2022-12-02 15:55:17 +00:00
Selase Krakani
a65c3ba079
FIX: Fix failing spec caused by unpersisted user instance (#19288)
Active Record's `to_sql` method seems to return an empty string instead
of the expected SQL query when called on a query involving an
unpersisted model instance.

This replaces the admin `user` used in the specs with a persisted instance.
2022-12-02 03:28:05 +00:00
Daniel Waterworth
1fbcf57767
Version bump to v2.8.13 (#19244) 2022-11-29 11:12:55 -06:00
Daniel Waterworth
fdc4984ade SECURITY: Filter tags in user notifications for visibility 2022-11-29 10:36:02 -06:00
Daniel Waterworth
f0b9ce42d6 FIX: When filtering tags for visibility, respect tag group permissions (#19152) 2022-11-29 10:36:02 -06:00
Martin Brennan
27d93b4658
FIX: Backport invite fixes from main (#19218)
Backports the following:

* 40e8912395
* bbcb69461f

Which were showing an error when users were
trying to claim invites multiple times and
a subsequent follow-up fix.
2022-11-28 15:15:00 +10:00
Martin Brennan
15823d4a50
Version bump to v2.8.12 (#19214) 2022-11-28 11:14:35 +10:00
Martin Brennan
131c5cff25
SECURITY: Hide notifications for inaccessible topics (#19209)
Filter notifications the user cannot see anymore
via guardian.can_see_topic_ids
2022-11-28 10:42:05 +10:00
David Taylor
bf30689059 Disable ember-cli-based CI tests for stable branch
The upgrade of node in our discourse_test docker image has caused these to start failing. Ember-cli assets are default-disabled on the stable branch, so there is little need to run these tests.
2022-11-17 14:17:45 +00:00
David Taylor
b25f469018 PERF: Update s3:expire_missing_assets to delete in batches (#18908)
Some sites may have thousands of stale assets - deleting them one-by-one is very slow.

Followup to e8570b5cc9
2022-11-17 14:17:45 +00:00
David Taylor
006a857272 Fix and improve s3:expire_missing_assets task (#18863)
- Ensure it works with prefixed S3 buckets
- Perform a sanity check that all current assets are present on S3 before starting deletion
- Remove the lifecycle rule configuration and delete expired assets immediately. This task should be run post-deploy anyway, so adding a 10-day window is not required
2022-11-17 14:17:45 +00:00
David Taylor
1291fc1afe PERF: Correct should_skip? logic in s3:upload (#18862)
This task is supposed to skip uploading if the asset is already present in S3. However, when a bucket 'folder path' was configured, this logic was broken and so the assets would be re-uploaded every time.

This commit fixes that logic to include the bucket 'folder path' in the check
2022-11-17 14:17:45 +00:00
Daniel Waterworth
c0971b19cb
FIX: Update GitImporter to match main (#18974)
Fixes:

 * An issue where the git url gets updated when it shouldn't,
 * Fetching from gitlab,
2022-11-14 12:28:00 -06:00
Martin Brennan
e67d5f222c
Version bump to v2.8.11 (#19008) 2022-11-14 13:14:01 +10:00
Martin Brennan
aca0f239c8
SECURITY: Prevent email from being nil in InviteRedeemer (#19005)
This commit adds some protections in InviteRedeemer to ensure that email
can never be nil, which could cause issues with inviting the invited
person to private topics since there was an incorrect inner join.

If the email is nil and the invite is scoped to an email, we just use
that invite.email unconditionally.  If a redeeming_user (an existing
    user) is passed in when redeeming an email, we use their email to
override the passed in email.  Otherwise we just use the passed in
email.  We now raise an error after all this if the email is still nil.
This commit also adds some tests to catch the private topic fix, and
some general improvements and comments around the invite code.

This commit also includes a migration to delete TopicAllowedUser records
for users who were mistakenly added to topics as part of the invite
redemption process.
2022-11-14 12:02:09 +10:00
Bianca Nenciu
3a985c82c7
SECURITY: Correctly render link title in draft preview (#18958)
The additional unescaping could cause link titles to be rendered
incorrectly.
2022-11-09 15:54:47 +02:00
David Taylor
ce28fd2e1d
Version bump to v2.8.10 (#18824) 2022-11-01 17:12:07 +00:00
David Taylor
7e4e8c8ad2
SECURITY: Fix invite link validation (stable) (#18818)
See https://github.com/discourse/discourse/security/advisories/GHSA-x8w7-rwmr-w278

Co-authored-by: Martin Brennan <martin@discourse.org>
2022-11-01 16:50:14 +00:00
David Taylor
ec9734bc42
SECURITY: Expand and improve SSRF Protections (stable) (#18816)
See https://github.com/discourse/discourse/security/advisories/GHSA-rcc5-28r3-23rr

Co-authored-by: OsamaSayegh <asooomaasoooma90@gmail.com>
Co-authored-by: Daniel Waterworth <me@danielwaterworth.com>
2022-11-01 16:34:12 +00:00
Alan Guo Xiang Tan
65820e8ac1
SECURITY: Restrict display of topic titles associated with user badges (#18768) (#18770)
Before this commit, we did not have guardian checks in place to determine if a
topic's title associated with a user badge should be displayed or not.
This means that the topic title of topics with restricted access
could be leaked to anon and users without access if certain conditions
are met. While we will not specify the conditions required, we have internally
assessed that the odds of meeting such conditions are low.

With this commit, we will now apply a guardian check to ensure that the
current user is able to see a topic before the topic's title is included
in the serialized object of a `UserBadge`.
2022-10-27 11:48:00 +08:00
Alan Guo Xiang Tan
365eef3a64
DEV: Introduce TopicGuardian#can_see_topic_ids method (#18692) (#18765)
Before this commit, there was no way for us to efficiently check an
array of topics for which a user can see. Therefore, this commit
introduces the `TopicGuardian#can_see_topic_ids` method which accepts an
array of `Topic#id`s and filters out the ids which the user is not
allowed to see. The `TopicGuardian#can_see_topic_ids` method is meant to
maintain feature parity with `TopicGuardian#can_see_topic?` at all
times so a consistency check has been added in our tests to ensure that
`TopicGuardian#can_see_topic_ids` returns the same result as
`TopicGuardian#can_see_topic?`. In the near future, the plan is for us
to switch to `TopicGuardian#can_see_topic_ids` completely but I'm not
doing that in this commit as we have to be careful with the performance
impact of such a change.

This method is currently not being used in the current commit but will
be relied on in a subsequent commit.
2022-10-27 07:46:28 +08:00
Michael Fitz-Payne
29f0bc4ea2 DEV(cache_critical_dns): add caching for MessageBus Redis hostname
We are already caching any DB_HOST and REDIS_HOST (and their
accompanying replicas), we should also cache the resolved addresses for
the MessageBus specific Redis. This is a noop if no MB redis is defined
in config. A side effect is that the MB will also support SRV lookup and
priorities, following the same convention as the other cached services.

The port argument was added to redis_healthcheck so that the script
supports a setup where Redis is running on a non-default port.

Did some minor refactoring to improve readability when filtering out the
CRITICAL_HOST_ENV_VARS. The `select` block was a bit confusing, so the
sequence was made easier to follow.

We were coercing an environment variable to an int in a few places, so
the `env_as_int` method was introduced to do that coercion in one place and
for convenience purposes default to a value if provided.

See /t/68301/30.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
bc8ad2a5d2 DEV(cache_critical_dns): add option to run once and exit
There are situations where a container running Discourse may want to
cache the critical DNS services without running the cache_critical_dns
service, for example running migrations prior to running a full bore
application container.

Add a `--once` argument for the cache_critical_dns script that will
only execute the main loop once, and return the status code for the
script to use when exiting. 0 indicates no errors occured during SRV
resolution, and 1 indicates a failure during the SRV lookup.

Nothing is reported to prometheus in run_once mode. Generally this
mode of operation would be a part of a unix pipeline, in which the exit
status is a more meaningful and immediate signal than a prometheus metric.

The reporting has been moved into it's own method that can be called
only when the script is running as a service.

See /t/69597.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
7804eb44e6 DOC(cache_critical_dns): add program description
Describes the behaviour and configuration of the cache_critical_dns
script, mainly cribbed from commit messages. Tries to make this program
a bit less of an enigma.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
cf86886448 DEV(cache_critical_dns): improve postgres_healthcheck
The `PG::Connection#ping` method is only reliable for checking if the
given host is accepting connections, and not if the authentication
details are valid.

This extends the healthcheck to confirm that the auth details are
able to both create a connection and execute queries against the
database.

We expect the empty query to return an empty result set, so we can
assert on that. If a failure occurs for any reason, the healthcheck will
return false.
2022-10-26 09:22:20 +10:00
Gabe Pacuilla
5340b09ad1 FIX(cache_critical_dns): use correct DISCOURSE_DB_USERNAME envvar (#16862) 2022-10-26 09:22:20 +10:00
Gabe Pacuilla
ab88591536 FIX(cache_critical_dns): use discourse database name and user by default (#16856) 2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
924ef90eed DEV(cache_critical_dns): add SRV priority tunables
An SRV RR contains a priority value for each of the SRV targets that
are present, ranging from 0 - 65535. When caching SRV records we may want to
filter out any targets above or below a particular threshold.

This change adds support for specifying a lower and/or upper bound on
target priorities for any SRV RRs. Any targets returned when resolving
the SRV RR whose priority does not fall between the lower and upper
thresholds are ignored.

For example: Let's say we are running two Redis servers, a primary and
cold server as a backup (but not a replica). Both servers would pass health
checks, but clearly the primary should be preferred over the backup
server. In this case, we could configure our SRV RR with the primary
target as priority 1 and backup target as priority 10. The
`DISCOURSE_REDIS_HOST_SRV_LE` could then be set to 1 and the target with
priority 10 would be ignored.

See /t/66045.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
cbf7d16d7c FIX: remove refresh seconds override on cache_critical_dns (#16572)
This removes the option to override the sleep time between caching of
DNS records. The override was invalid because `''.to_i` is 0 in Ruby,
causing a tight loop calling the `run` method.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
8293f11f53 FIX: cache_critical_dns - add TLS support for Redis healthcheck
For Redis connections that operate over TLS, we need to ensure that we
are setting the correct arguments for the Redis client. We can utilise
the existing environment variable `DISCOURSE_REDIS_USE_SSL` to toggle
this behaviour.

No SSL verification is performed for two reasons:
- the Discourse application will perform a verification against any FQDN
  as specified for the Redis host
- the healthcheck is run against the _resolved_ IP address for the Redis
  hostname, and any SSL verification will always fail against a direct
  IP address

If no SSL arguments are provided, the IP address is never cached against
the hostname as no healthy address is ever found in the HealthyCache.
2022-10-26 09:22:20 +10:00
Michael Fitz-Payne
971409741f DEV: refactor cache_critical_dns for SRV RR awareness
Modify the cache_critical_dns script for SRV RR awareness. The new
behaviour is only enabled when one or more of the following environment
variables are present (and only for a host where the `DISCOURSE_*_HOST_SRV`
variable is present):
- `DISCOURSE_DB_HOST_SRV`
- `DISCOURSE_DB_REPLICA_HOST_SRV`
- `DISCOURSE_REDIS_HOST_SRV`
- `DISCOURSE_REDIS_REPLICA_HOST_SRV`

Some minor changes in refactor to original script behaviour:
- add Name and SRVName classes for storing resolved addresses for a hostname
- pass DNS client into main run loop instead of creating inside the loop
- ensure all times are UTC
- add environment override for system hosts file path and time between DNS
  checks mainly for testing purposes

The environment variable for `BUNDLE_GEMFILE` is set to enables Ruby to
load gems that are installed and vendored via the project's Gemfile.
This script is usually not run from the project directory as it is
configured as a system service (see
71ba9fb7b5/templates/cache-dns.template.yml (L19))
and therefore cannot load gems like `pg` or `redis` from the default
load paths. Setting this environment variable configures bundler to look
in the correct project directory during it's setup phase.

When a `DISCOURSE_*_HOST_SRV` environment variable is present, the
decision for which target to cache is as follows:
- resolve the SRV targets for the provided hostname
- lookup the addresses for all of the resolved SRV targets via the
  A and AAAA RRs for the target's hostname
- perform a protocol-aware healthcheck (PostgreSQL or Redis pings)
- pick the newest target that passes the healthcheck

From there, the resolved address for the SRV target is cached against
the hostname as specified by the original form of the environment
variable.

For example: The hostname specified by the `DISCOURSE_DB_HOST` record
is `database.example.com`, and the `DISCOURSE_DB_HOST_SRV` record is
`database._postgresql._tcp.sd.example.com`. An SRV RR lookup will return
zero or more targets. Each of the targets will be queried for A and AAAA
RRs. For each of the addresses returned, the newest address that passes
a protocol-aware healthcheck will be cached. This address is cached so
that if any newer address for the SRV target appears we can perform a
health check and prefer the newer address if the check passes.

All resolved SRV targets are cached for a minimum of 30 minutes in memory
so that we can prefer newer hosts over older hosts when more than one target
is returned. Any host in the cache that hasn't been seen for more than 30
minutes is purged.

See /t/61485.
2022-10-26 09:22:20 +10:00
David Taylor
9524c1320a DEV: Include DISCOURSE_REDIS_REPLICA_HOST in cache_critical_dns (#15877)
This is the replacement for DISCOURSE_REDIS_SLAVE_HOST
2022-10-26 09:22:20 +10:00
Alan Guo Xiang Tan
689ba22db0
DEV: Remove harded id when fabricating in tests (#18729) (#18730)
Hardcoding ids always lead to sadness for our test suite
2022-10-25 06:33:36 +08:00
Alan Guo Xiang Tan
6c97cc1834
DEV: Fabricate instead of just building topic, post and user in tests (#18698) (#18717)
Building does not persist the object in the database which is
unrealistic since we're mostly dealing with persisted objects in
production.

In theory, this will result our test suite taking longer to run since we
now have to write to the database. However, I don't expect the increase
to be significant and it is actually no different than us adding new
tests which fabricates more objects.
2022-10-24 07:28:02 +08:00
Jarek Radosz
1503ec07c5
Version bump to v2.8.9 (#18430) 2022-09-29 21:00:32 +02:00
Jarek Radosz
65017fe920
SECURITY: moderator shouldn't be able to import a theme via API (stable) (#18420)
* SECURITY: moderator shouldn't be able to import a theme via API.
* DEV: apply `AdminConstraint` for all the "themes" routes.

Co-authored-by: Vinoth Kannan <svkn.87@gmail.com>
2022-09-29 20:13:34 +02:00
Jarek Radosz
4302097b3b
SECURITY: Prevent arbitrary file write when decompressing files (stable) (#18423)
* SECURITY: Prevent arbitrary file write when decompressing files
* FIX: Allow decompressing files into symlinked directories

Co-authored-by: OsamaSayegh <asooomaasoooma90@gmail.com>
Co-authored-by: Gerhard Schlager <gerhard.schlager@discourse.org>
2022-09-29 20:07:58 +02:00
Martin Brennan
a896a69c50
SECURITY: Limit user profile field length (#18304)
Adds limits to location and website fields at model and DB level to
match the bio_raw field limits. A limit cannot be added at the DB level
for bio_raw because it is a postgres text field.

The migration here uses version `6.1` instead of `7.0` since `stable`
is not on that version of rails yet, otherwise this is the same as `beta`
apart from also removing the new tests which caused too many conflicts.

Co-authored-by: Alan Guo Xiang Tan gxtan1990@gmail.com
2022-09-21 13:49:25 +10:00
Loïc Guitaut
13517cde7e Version bump to 2.8.8 2022-08-10 15:05:39 +02:00
Krzysztof Kotlarek
4fcffd3fae SECURITY: Limit email invitations to topic 2022-08-10 11:47:14 +02:00
Roman Rizzi
7b8f74439e
Version bump to v2.8.7 (#17700) 2022-07-27 17:28:39 -03:00
Roman Rizzi
af1cb735db
SECURITY: Prevent abuse of the update_activation_email route (stable) 2022-07-27 23:09:09 +03:00
Roman Rizzi
7af25544c3
SECURITY: Do not cache error responses for static assets (stable) 2022-07-27 22:58:38 +03:00
David Taylor
f0ef186a4e
FIX: Allow Symbol objects to be deserialized in PostRevision (stable) (#17512)
Followup to bb287c6c74
2022-07-15 13:16:20 +01:00
David Taylor
5d2ecce3f6
FIX: Allow Time objects to be deserialized in PostRevision (stable) (#17502)
Followup to bb287c6c74
2022-07-15 00:17:53 +01:00
David Taylor
c75ec7335d
Version bump to v2.8.6 (#17472) 2022-07-13 12:40:16 +01:00
David Taylor
bb287c6c74
SECURITY: Bump Rails to 6.1.6.1 (stable) (#17470)
https://discuss.rubyonrails.org/t/81017
2022-07-13 11:19:55 +01:00
Gerhard Schlager
3d1bbf7446 FIX: Logout could fail due to cached user
Logging out failed when the current user was cached by an instance of `Auth::DefaultCurrentUserProvider` and `#log_off_user` was called on a different instance of that class.

Co-authored-by: Sam <sam.saffron@gmail.com>
2022-07-04 17:01:45 +02:00
Gerhard Schlager
61ed83ecfc FIX: Incorrect currentUser could be cached for requests with API key (#17279)
This happened when a middleware accessed the `currentUser` before a controller had a chance to populate the `action_dispatch.request.path_parameters` env variable. In that case Discourse would always cache `nil` as `currentUser`.
2022-07-04 17:01:45 +02:00
Penar Musaraj
61cf791929
Version bump to v2.8.5 (#17187) 2022-06-21 15:05:00 -04:00
Daniel Waterworth
7616e9b540
SECURITY: Validate email constraints when trying to redeem an invite (#17182)
In certain situations, a logged in user can redeem an invite with an email that
either doesn't match the invite's email or does not adhere to the email domain
restriction of an invite link. The impact of this flaw is aggrevated
when the invite has been configured to add the user that accepts the
invite into restricted groups.

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2022-06-21 13:25:10 -05:00
Blake Erickson
cf94e52f78
Version bump to v2.8.4 (#17075) 2022-06-13 15:04:02 -06:00
Blake Erickson
918c296fe8
SECURITY: banner-info (#17071) (#17073) 2022-06-13 11:47:44 -06:00
Alan Guo Xiang Tan
036467aac3
FIX: Approves user when redeeming an invite for invites only sites (#16987)
When a site has `SiteSetting.invite_only` enabled, we create a
`ReviewableUser`record when activating a user if the user is not
approved. Therefore, we need to approve the user when redeeming an
invite.

There are some uncertainties surrounding why a `ReviewableRecord` is
created for a user in an invites only site but this commit does not seek
to address that.

Follow-up to 7c4e2d33fa
2022-06-03 14:50:58 +08:00
Alan Guo Xiang Tan
576354072e
DEV: Fix auto start for wizard qunit tests (#16988)
`run-qunit.js` does not expect QUnit tests to start automatically but
our wizard QUnit setup did not respect the `qunit_disable_auto_start`
URL param. Hence, tests would start running automatically and when a
subsequent `QUnit.start()` function call is made, we ended up getting a
`QUnit.start cannot be called inside a test context.` error.

This error can be consistently reproduced in the `discourse:discourse_test` container but not in
the local development environment. I do not know why and did not feel
like it is important at this point in time to know why.
2022-06-03 12:44:42 +08:00
Gerhard Schlager
5c91d9a629
SECURITY: Remove auto approval when redeeming an invite (#16976)
This security fix affects sites which have `SiteSetting.must_approve_users`
enabled. There are intentional and unintentional cases where invited
users can be auto approved and are deemed to have skipped the staff approval process.
Instead of trying to reason about when auto-approval should happen, we have decided that
enabling the `must_approve_users` setting going forward will just mean that all new users
must be explicitly approved by a staff user in the review queue. The only case where users are auto
approved is when the `auto_approve_email_domains` site setting is used.

Co-authored-by: Alan Guo Xiang Tan <gxtan1990@gmail.com>
2022-06-02 16:11:04 +02:00
David Taylor
a0c141d6ac
FIX: Ensure theme JavaScript cache get consistent SHA1 digest (stable backport) (#16669)
(Stable backport of 7ed899f)

There is a couple of layers of caching for theme JavaScript in Discourse:

The first layer is the `javascript_caches` table in the database. When a theme
with JavaScript files is installed, Discourse stores each one of the JavaScript
files in the `theme_fields` table, and then concatenates the files, compiles
them, computes a SHA1 digest of the compiled JavaScript and store the results
along with the SHA1 digest in the `javascript_caches` table.

Now when a request comes in, we need to render `<script>` tags for the
activated theme(s) of the site. To do this, we retrieve the `javascript_caches`
records of the activated themes and generate a `<script>` tag for each record.
The `src` attribute of these tags is a path to the `/theme-javascripts/:digest`
route which simply responds with the compiled JavaScript that has the requested
digest.

The second layer is a distributed cache whose purpose is to make rendering
`<script>` a lot more efficient. Without this cache, we'd have to query the
`javascript_caches` table to retrieve the SHA1 digests for every single
request. So we use this cache to store the `<script>` tags themselves so that
we only have to retrieve the `javascript_caches` records of the activated
themes for the first request and future requests simply get the cached
`<script>` tags.

What this commit does it ensures that the SHA1 digest in the
`javascript_caches` table stay the same across compilations by adding an order
by id clause to the query that loads the `theme_fields` records. Currently, we
specify no order when retrieving the `theme_fields` records so the order in
which they're retrieved can change across compilations and therefore cause the
SHA1 to change even though the individual records have not changed at all.

An inconsistent SHA1 digest across compilations can cause the database cache
and the distributed cache to have different digests and that causes the
JavaScript to fail to load (and if the theme heavily customizes the site, it
gives the impression that the site is broken) until the cache is cleared.

This can happen in busy sites when 2 concurrent requests recompile the
JavaScript files of a theme at the same time (this can happen when deploying a
new Discourse version) and request A updates the database cache after request B
did, and request B updates the distributed cache after request A did.

Internal ticket: t60783.

Co-authored-by: David Taylor <david@taylorhq.com>
Co-authored-by: Osama Sayegh <asooomaasoooma90@gmail.com>
2022-05-06 11:10:40 +01:00
David Taylor
d8b68e00c9
FIX: Ensure values are escaped in select-kit dropdowns (#16586)
The values in Discourse dropdown menus only come from admin-defined strings, not unsanitised end-user input, so this lack of escaping was not exploitable.
2022-04-28 16:31:41 +01:00
Penar Musaraj
bb57be95f0 DEV: Cleanup body.scrollTop usage (#16445)
All current browser treat the HTML document (not the body element) as
the scrollable document element. Hence in all current browsers,
`document.body.scrollTop` returns 0. This commit removes all usage of
this property, because it is effectively 0.

Co-authored-by: David Taylor <david@taylorhq.com>
2022-04-14 12:45:34 -04:00
Penar Musaraj
9a9a29b24b FIX: Buggy topic scrolling on iOS 12 (#16422) 2022-04-14 12:45:34 -04:00
Penar Musaraj
a9a643bcdc
Version bump to v2.8.3 2022-04-14 10:08:37 -04:00
David Taylor
b72b0dac10
SECURITY: Ensure user-agent-based responses are cached separately (stable) (#16476) 2022-04-14 14:26:00 +01:00
Alan Guo Xiang Tan
3ac1b3a5c9 SECURITY: Update Nokogiri to 1.13.4.
Nokogiri 1.13.4 updates zlib to 1.2.12 to address CVE-2018-25032.

https://github.com/sparklemotion/nokogiri/security/advisories/GHSA-v6gp-9mmm-c6p5
https://nvd.nist.gov/vuln/detail/CVE-2018-25032
2022-04-12 15:19:46 +08:00
Jarek Radosz
6bbc822495 DEV: Don't check this.element in @afterRender (#16033)
This would allow to use the decorator in tag-less components and in controllers.
2022-04-11 13:03:54 +08:00
Alan Guo Xiang Tan
72c69a644f DEV: Add pretender endpoint for category visible groups.
This was causing our build to become flaky.
2022-04-11 13:03:54 +08:00
Alan Guo Xiang Tan
3d581ce159 SECURITY: Category group permissions leaked to normal users.
After this commit, category group permissions can only be seen by users
that are allowed to manage a category. In the past, we inadvertently
included a category's group permissions settings in `CategoriesController#show`
and `CategoriesController#find_by_slug` endpoints for normal users when
those settings are only a concern to users that can manage a category.
2022-04-08 11:04:59 +02:00
Bianca Nenciu
dcbd788412 FIX: Serialize permissions for everyone group
The permissions for the 'everyone' group were not serialized because
the list of groups a user can view did not include it. This bug was
introduced in commit dfaf9831f7.
2022-04-08 11:04:59 +02:00
Martin Brennan
f0574564c4 DEV: Fix failing share topic tests (#16309)
Since 3fd7b31a2a some tests
were failing with this error:

> Error: Unhandled request in test environment: /c/feature/find_by_slug.json
> (GET) at http://localhost:7357/assets/test-helpers.js

This commit fixes the issue by adding the missing pretender. Also
noticed while fixing this that the parameter for the translation
was incorrect -- it was `group` instead of `groupNames`, so that
is fixed here too, along with moving the onShow functions into
@afterRender decorated private functions. There is no need for the
appevent listeners.
2022-04-08 11:04:59 +02:00
Bianca Nenciu
1516dd75f5 FIX: Show restricted groups warning when necessary (#16236)
It was displayed for the "everyone" group too, but that was not
necessary.
2022-04-08 11:04:59 +02:00
Alan Guo Xiang Tan
7b5ef41a43 DEV: Restore order assertion in category serializer tests. (#16344)
Our group fabrication creates groups with name "my_group_#{n}" where n
is the sequence number of the group being created. However, this can
cause the test to be flaky if and when a group with name `my_group_10`
is created as it will be ordered before
`my_group_9`. This commits makes the group names determinstic to
eliminate any flakiness.

This reverts commit 558bc6b746.
2022-04-01 09:17:58 +08:00
David Taylor
62cde96c70 DEV: Fix flaky specs (#16340)
`group_permissions` are not serialized in a consistent order

Follow-up to dfaf9831f7
2022-04-01 09:17:58 +08:00
Alan Guo Xiang Tan
09e7dd00b8
SECURITY: Avoid leaking private group name when viewing category. (#16339)
In certain instances when viewing a category, the name of a group with
restricted visilbity may be revealed to users which do not have the
required permission.
2022-03-31 15:07:48 +08:00
Martin Brennan
bd0f10a50b
SECURITY: Hide private categories in user activity export (#16276)
In some of the user's own activity export data,
we sometimes showed a secure category's name or
exposed the existence of a secure category.
2022-03-24 15:56:50 +10:00
Neil Lalonde
74ce2fe2e7
Version bump to v2.8.2 2022-03-22 14:51:41 -04:00
Alan Guo Xiang Tan
79da89fd06
DEV: Don't load bundler when installing plugin gem. (#16176)
when bundler is loaded, it sets the `RUBYOPT` environment variable to setup bundler. However, it was causing weird errors like the following when we try to install
custom plugin gems into a specific directory.

```
/home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/source/git.rb:214:in `rescue in load_spec_files': https://github.com/discourse/mail.git is not yet checked out. Run `bundle install` first. (Bundler::GitError)
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/source/git.rb:210:in `load_spec_files'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/source/path.rb:107:in `local_specs'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/source/git.rb:178:in `specs'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/lazy_specification.rb:88:in `__materialize__'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/spec_set.rb:75:in `block in materialize'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/spec_set.rb:72:in `map!'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/spec_set.rb:72:in `materialize'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/definition.rb:468:in `materialize'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/definition.rb:190:in `specs'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/definition.rb:238:in `specs_for'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/runtime.rb:18:in `setup'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler.rb:151:in `setup'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/setup.rb:20:in `block in <top (required)>'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/ui/shell.rb:136:in `with_level'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/ui/shell.rb:88:in `silence'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/gems/2.7.0/gems/bundler-2.3.5/lib/bundler/setup.rb:20:in `<top (required)>'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:85:in `require'
	from /home/tgxworld/.asdf/installs/ruby/2.7.5/lib/ruby/site_ruby/2.7.0/rubygems/core_ext/kernel_require.rb:85:in `require'
```
2022-03-18 11:27:20 +08:00
Alan Guo Xiang Tan
43c744cdc8
DEV: Pull compatible version for plugins in Github test workflow. (#16212)
We have 3 branches which we care about, main, beta and stable.
However, each of this branch has different compatibilties with plugins
and we want to respect that.
2022-03-18 10:30:43 +08:00
Alan Guo Xiang Tan
1d2654f91f
DEV: Backport Github test workflow to stable. (#16210) 2022-03-17 14:02:45 +08:00
David Taylor
d7b48d0229
FIX: Handle nil values in DistributedCache#defer_get_set (stable) (#15980)
Themes often cache `nil` values in a DistributedCache. This bug meant that we were re-calculating some values on every request, AND triggering message-bus publishing on every request.

This fix should provide a significant performance improvement for busy sites.
2022-02-18 08:51:14 +00:00
Andrei Prigorshnev
2c8f62e271
FIX: backport caret moves to a wrong position when uploading an image via toolbar (#15865)
* FIX: Caret moves to a wrong position when uploading an image via toolbar

* Skip the test
2022-02-17 13:44:21 +11:00
Bianca Nenciu
0674d07cdf
FIX: Defer upload extension check for iOS (#15890)
accept HTML attribute is not fully supported on iOS yet and can contain
only MIME types. This changes the input to allow all files and the
extension check is performed later in JavaScript.
2022-02-15 19:57:58 +02:00
communiteq
247f70f79c
Fix bug regarding Chat on stable (#15954) 2022-02-15 12:40:48 -05:00
Krzysztof Kotlarek
cb9678ed34 Version bump to v2.8.1 2022-02-14 17:17:31 +11:00
Krzysztof Kotlarek
76195216ff SECURITY: Onebox response timeout and size limit (#15927)
Validation to ensure that Onebox request is no longer than 10 seconds and response size is not bigger than 1 MB
2022-02-14 12:13:22 +11:00
Dan Ungureanu
0b4e16aa2d
FEATURE: RS512, RS384 and RS256 COSE algorithms (#15868)
* FEATURE: RS512, RS384 and RS256 COSE algorithms

These algorithms are not implemented by cose-ruby, but used in the web
authentication API and were marked as supported.

* FEATURE: Use all algorithms supported by cose-ruby

Previously only a subset of the algorithms were allowed.
2022-02-09 13:56:45 +02:00
David Taylor
1cfe5b5c26
Update translations (stable) (#15819)
Combination of 0dfaaf49a5 and 022480b461

Co-authored-by: Discourse Translator Bot <discourse.translator.bot@gmail.com>
2022-02-04 17:00:25 +00:00
Martin Brennan
7dd9dd848a
FIX: Table pasting issues with uppy (#15787) (#15812)
When changing to uppy for file uploads we forgot to add
these conditions to the paste event from 9c96511ec4

Basically, if you are pasting more than just a file (e.g. text,
html, rtf), then we should not handle the file and upload it, and
instead just paste in the text. This causes issues with spreadsheet
tools, that will copy the text representation and also an image
representation of cells to the user's clipboard.

This also moves the paste event for composer-upload-uppy to the
element found by the `editorClass` property, so it shares the paste
event with d-editor (via TextareaTextManipulation), which makes testing
this possible as the ember paste bindings are not picked up unless both
paste events are on the same element.
2022-02-04 11:44:30 +11:00
Penar Musaraj
be72ae8c49
A11Y: Switch to using autocomplete="off" (#15802) 2022-02-03 17:45:25 +01:00
Natalie Tay
2d7e2b3810
FIX: Only block domains at the final destination (#15689) (#15783)
In an earlier PR, we decided that we only want to block a domain if 
the blocked domain in the SiteSetting is the final destination (/t/59305). That 
PR used `FinalDestination#get`. `resolve` however is used several places
 but blocks domains along the redirect chain when certain options are provided.

This commit changes the default options for `resolve` to not do that. Existing
users of `FinalDestination#resolve` are
- `Oneboxer#external_onebox`
- our onebox helper `fetch_html_doc`, which is used in amazon, standard embed 
and youtube
  - these folks already go through `Oneboxer#external_onebox` which already
  blocks correctly
2022-02-03 09:42:06 +08:00
Martin Brennan
7979708f17
DEV: Remove jQuery UI vendor dependencies (#15782)
Combines 68fe6903f7 and
7b7e707fa2.

We no longer use jQuery UI for anything since getting
rid of jQuery file uploader in 667a8a6,
so we can safely remove these now.

Also removes the blueimp-file-upload and jquery.iframe-transport
dependencies that were formerly used by jQuery file uploader
2022-02-03 11:19:50 +10:00
Neil Lalonde
3a5b75435e
Version bump to v2.8.0 2022-01-27 10:22:23 -05:00
Neil Lalonde
9830b192f3
Merge diffs from main 2022-01-27 10:12:37 -05:00
Neil Lalonde
42caef4719
Merge main 2022-01-27 10:10:35 -05:00
Neil Lalonde
3a126c134e
Version bump to v2.7.13 2022-01-13 10:16:51 -05:00
Dan Ungureanu
c7a6d9bc3a
SECURITY: Do not sign in unapproved users (#15552) 2022-01-13 10:42:48 +02:00
David Taylor
909de9b36c
FIX: Bypass service worker on the SSO path (#15558) (#15560)
This is a workaround a behavior change in Chromium v97.
The following text was sent to the blink-dev mailing list:

> This change broke a SingleSignOn login on the FOSS software Discourse. We have a flow like:
>
> 1. User visits forum.siteA.com, click login
> 2. Gets redirected to idp.siteB.com
> 3. Fills login details
> 4. Gets redirected to forum.siteA.com/session/sso_login?parameters
> 5. Gets redirected to forum.siteA.com/homepage
>
> On step 4, the response includes a `set-cookie` header, with proper `HttpOnly; SameSite=Lax; Secure `and set. But if there is an active service worker, the login will fail as that cookie will be rejected by Chromium due to SameSite rules now.
>
> t=2971 [st=258]        COOKIE_INCLUSION_STATUS
>                        --> domain = "forum.siteA.com"
>                        --> name = "_t"
>                        --> operation = "store"
>                        --> path = "/"
>                        --> status = "EXCLUDE_SAMESITE_LAX, DO_NOT_WARN"
>
> The service worker is a vanilla WorkboxJS service worker that intercepts all GETs with the "Network First" strategy.
>
> Disabling the service worker or using Firefox results in a successful login. There is no warning in either DevTools network tab nor the console that the cookie was rejected.
>
> Chrome 96: login works
> Chrome 97: login does not work
> Chrome 98: login does not work
>
> Is this expected behavior? Even if the request `GET forum.siteA.com` was initiated because of a redirect from a different domain, is it expected that Chrome will silently drop same site cookies from forum.siteA.com?

Co-authored-by: Rafael dos Santos Silva <xfalcox@gmail.com>
2022-01-13 00:08:33 +00:00
David Taylor
5cfe42474a
FIX: LOAD_PLUGINS=0 in dev/prod, warn in plugin:pull_compatible_all (stable) (#15538)
The `plugin:pull_compatible_all` task is intended to take incompatible plugins and downgrade them to an earlier version. Problem is, when running the rake task in development/production environments, the plugins have already been activated. If an incompatible plugin raises an error in `plugin.rb` then the rake task will be unable to start.

This commit centralises our LOAD_PLUGINS detection, adds support for LOAD_PLUGINS=0 in dev/prod, and adds a warning to `plugin:pull_compatible_all` if it's run with plugins enabled.
2022-01-11 12:30:38 +00:00
Alan Guo Xiang Tan
a09778aba9 SECURITY: Advanced group search did not respect visiblity of groups. 2022-01-10 13:49:45 +08:00
Bianca Nenciu
9a97ce1899
SECURITY: Hide user's bio if profile is restricted (#15448)
The bio was sometimes visible in the meta tags even though it it should
not have been.
2022-01-07 14:19:48 +02:00
Arpit Jalan
75fa5ee748 SECURITY: only show user suggestions with regular post (#15436) 2022-01-03 13:56:46 +05:30
Neil Lalonde
81b398030e
Version bump to v2.7.12 2021-12-21 13:27:14 -05:00
Alan Guo Xiang Tan
7a8ec129fb SECURITY: Disable MessageBus::Diagnostics.
MessageBus::Diagnostics allows anyone with access to carry out certain
operations that may result in a denial of service. The impact of this is
greater on multisiite clusters.
2021-12-17 14:45:13 +08:00
Neil Lalonde
30bc65af70
Version bump to v2.7.11 2021-12-01 11:45:57 -05:00
David Taylor
0c6b9df77b
FIX: Validate number of votes allowed per poll per user (stable) (#15158)
Backport of 1d0faedfbc
2021-12-01 16:42:39 +00:00
David Taylor
982f23e1f2
SECURITY: Remove ember-cli specific response from application routes (stable) (#15154)
Under some conditions, these varied responses could lead to cache poisoning, hence the 'security' label.

For the stable branch, we are disabling the use of Ember CLI against production sites. A new implementation has been added to the tests-passed/beta branches
2021-12-01 16:02:45 +00:00
Natalie Tay
cdaf7f4bb3
SECURITY: Only show tags to users with permission (#15148) 2021-12-01 10:33:10 +08:00
Martin Brennan
715d4de981
SECURITY: Strip unrendered unicode bidirectional chars in code blocks (#15032)
When rendering the markdown code blocks we replace the
offending characters in the output string with spans highlighting a textual
representation of the character, along with a title attribute with
information about why the character was highlighted.

The list of characters stripped by this fix, which are the bidirectional
characters considered relevant, are:

U+202A
U+202B
U+202C
U+202D
U+202E
U+2066
U+2067
U+2068
U+2069
2021-11-22 10:46:07 +10:00
Neil Lalonde
626a0e207e
Version bump to v2.7.10 2021-11-15 11:18:57 -05:00
David Taylor
73f64b8299
SECURITY: Ensure _forum_session cookies cannot be reused between sites (stable) (#14949)
This only affects multisite Discourse instances (where multiple forums are served from a single application server). The vast majority of self-hosted Discourse forums do not fall into this category.

On affected instances, this vulnerability could allow encrypted session cookies to be re-used between sites served by the same application instance.
2021-11-15 15:50:17 +00:00
David Taylor
2da0001965
SECURITY: Disallow caching of MIME/Content-Type errors (#14939)
This will sign intermediary proxies and/or misconfigured CDNs to not
cache those error responses.

Co-authored-by: Rafael dos Santos Silva <xfalcox@gmail.com>
2021-11-15 12:02:56 +00:00
Neil Lalonde
a1dcf3a50c
Version bump to v2.7.9 2021-10-20 17:24:11 -04:00
David Taylor
fa3c46cf07
SECURITY: Improve validation of SNS subscription confirm (#14672)
An upstream validation bug in the aws-sdk-sns library could enable RCE under certain circumstances. This commit updates the upstream gem, and adds additional validation to provide defense-in-depth.
2021-10-20 22:20:35 +01:00
Bianca Nenciu
98b0621d53 SECURITY: Escape watched word in error message (#14434) 2021-09-24 13:38:05 +03:00
Neil Lalonde
18b6f4ecf6
Version bump to v2.7.8 2021-09-01 13:18:17 -04:00
Blake Erickson
7cd207761a
SECURITY: escape cat name (#14155) 2021-08-25 18:14:10 -06:00
Alan Guo Xiang Tan
c6ef6632c6 SECURITY: User's read state for topic is leaked to unauthorized clients.
A user's read state for a topic such as the last read post number and the notification level is exposed.
2021-08-12 12:44:39 +08:00
jbrw
d11b6751bb
SECURITY: Destroy EmailToken when EmailChangeRequest is destroyed (#13950) 2021-08-06 19:27:09 -04:00
Bianca Nenciu
4c748f7f54 SECURITY: Sanitize d-popover attributes (#13958) 2021-08-05 16:40:48 +03:00
Neil Lalonde
b47c5f69d8
Version bump to v2.7.7 2021-07-23 10:53:32 -04:00
Alan Guo Xiang Tan
cc7b8d5f9f
DEV: Make rubocop happy. 2021-07-23 16:39:39 +08:00
Alan Guo Xiang Tan
dbdf61196d
SECURITY: Don't leak user of previous whisper post when deleting a topic.
A topic's last poster can be incorrectly set to a user of a whisper post
if the whisper post is before the last post and the last post is
deleted.
2021-07-23 16:39:37 +08:00
Alan Guo Xiang Tan
680024f907
SECURITY: Do not reveal post whisperer in personal messages.
Prior to this fix, post whisperer in personal messages are revealed in
the topic's participants list even though non-staff users are unable to
see the whisper.
2021-07-23 16:39:29 +08:00
Neil Lalonde
ae224045a6
Version bump to v2.7.6 2021-07-15 14:37:25 -04:00
David Taylor
ad7c7f819d
SECURITY: Sanitize YouTube Onebox data (stable) (#13749)
CVE-2021-32764
2021-07-15 19:32:47 +01:00
Neil Lalonde
a94a623009
Version bump to v2.7.5 2021-07-08 09:43:45 -04:00
Arpit Jalan
d54f7c1f42 SECURITY: do not follow canonical links 2021-07-07 14:11:32 +05:30
Bianca Nenciu
6a7e628037 FIX: TL4 users cannot delete others posts (#13554) 2021-07-06 12:11:29 +03:00
Joffrey JAFFEUX
023f5ae8e0
SECURITY: prevents onebox to hang too long on connect (#13481) 2021-06-22 17:19:13 +02:00
Penar Musaraj
fe1e1903eb
Version bump to v2.7.4 2021-06-09 14:00:41 -04:00
Robin Ward
db826335e9
DEV: Add support for class properties in babel (#13189)
This allows us to start using JS classes instead of Ember's classes.
2021-06-09 13:53:43 -04:00
Penar Musaraj
cf8610cee1
DEV: Enable optional chaining in all contexts (#13180)
* Revert "FIX: We can't use `?.` yet (#13168)"
2021-06-09 13:52:30 -04:00
Neil Lalonde
859dfac6c6
Version bump to v2.7.3 2021-06-08 11:36:25 -04:00
Régis Hanol
98f92d2e23 SECURITY: XSS in bookmarks list (#13311)
We should use `fancy_title` instead of `title` when displaying a topic title to ensure only the allowed html is not escaped.
2021-06-07 16:59:12 +02:00
Neil Lalonde
81070b323f
Version bump to v2.7.2 2021-06-04 11:23:14 -04:00
Sam
5db39cce93
UX: unconditionally focus modals (#13179)
Previously auto focus would only work on modals that include buttons or
inputs.

To avoid a situation where information modals such as keyboard shortcuts
do not get focus, simply focus on the close button as a fallback.
2021-06-04 10:35:12 -04:00
Robin Ward
45dca791b0
UX: Add auto focus to hamburger and user menu dropdowns (#13165) 2021-06-04 10:35:04 -04:00
Bianca Nenciu
8170563693
FIX: Make poll options tabbable (#13159) 2021-06-04 10:34:49 -04:00
Sam
22e9acc797
UX: Improve navigation on topic lists for screen readers (#13153)
Previously we had no role set for various topic links, nor did we have any
headers.

This teaches screen readers that topic links in topic lists are to be treated
as H2. We opted for this less radical change cause a change of the element
type would probably result in many broken themes.

Confirmed on NVDA you can very quickly breeze through topic lists now. Minor
edge case is pinned topics which can be a bit annoying due to multiple links.
2021-06-04 10:34:40 -04:00
Sam
d444a8a400
UX: provide a region for various topic actions (#13152)
This makes it much easier to reply to topics / bookmark topics and so on

Previously topic buttons had no region
2021-06-04 10:34:31 -04:00
Robin Ward
16e1ea938c
FIX: Better focus support for modals (#13147) 2021-06-04 10:34:20 -04:00
Sam
873eb405cd
UX: add ARIA region role to posts (#13130)
NVDA does not detect HTML5 articles as regions. This explicitly sets a
region with an aria-label denoting post numbers making it much easier to
know where you are in a topic.

Note role: article which is more semantically correct is not respected by
NVDA d/D shortcut, hence the much more generic "region" role.
2021-06-04 10:34:13 -04:00
Kris
8e0a669aa5
A11Y: Fix post control and user-menu focus styles (#13118) 2021-06-04 10:34:05 -04:00
dependabot[bot]
2674078b97
Build(deps): Bump nokogiri from 1.11.4 to 1.11.5 (#13107)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.4 to 1.11.5.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.4...v1.11.5)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-04 10:33:57 -04:00
Kris
bb59e4ca61
UX: Fix theme upload width, remove class clash, prettier (#13071)
* UX: fix width & theme upload modal class clash

* remove unneeded class

* unprettier hbs

* add back unicode emoji

* add newline
2021-06-04 10:33:49 -04:00
dependabot[bot]
d803095451
Build(deps): Bump nokogiri from 1.11.3 to 1.11.4 (#13074)
Bumps [nokogiri](https://github.com/sparklemotion/nokogiri) from 1.11.3 to 1.11.4.
- [Release notes](https://github.com/sparklemotion/nokogiri/releases)
- [Changelog](https://github.com/sparklemotion/nokogiri/blob/main/CHANGELOG.md)
- [Commits](https://github.com/sparklemotion/nokogiri/compare/v1.11.3...v1.11.4)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-06-04 10:33:40 -04:00
Neil Lalonde
8562c1d098
Version bump to v2.7.1 2021-06-03 14:55:45 -04:00
Penar Musaraj
7d06980cc5
SECURITY: Do not allow unauthorized access to category edit UI (#13252) 2021-06-03 14:35:27 -04:00
Penar Musaraj
5f5301d478
FIX: Close hyperlink modal on ESC key (#13166) 2021-06-03 14:35:00 -04:00
Penar Musaraj
f8bab65425
FIX: Disable lightboxing of animated images (#13099) 2021-06-03 14:34:36 -04:00
Neil Lalonde
ccf207f12e
Version bump to v2.7.0 2021-05-18 14:28:06 -04:00
Neil Lalonde
2c399a84fe
Merge master 2021-05-18 14:09:54 -04:00
Neil Lalonde
f73cdbbd2f
Version bump to v2.6.7 2021-05-10 10:29:43 -04:00
David Taylor
23ac6fc5e0
SECURITY: Bump Rails to 6.0.3.7 (#12965)
This includes fixes for:
- CVE-2020-8264
- CVE-2021-22881
- CVE-2021-22885
- CVE-2021-22904
- CVE-2021-22902
2021-05-06 13:37:13 +01:00
Neil Lalonde
e34c29aa7f
Version bump to v2.6.6 2021-04-29 11:26:20 -04:00
Bianca Nenciu
14e53c59b2
FIX: Gracefully handle inline images in emails (#12855) 2021-04-29 10:38:49 +03:00
Bianca Nenciu
1525653dff
FIX: Replace use of regular expression (#12838)
It used a regular expression to check if message IDs were in RFC format.
2021-04-27 17:13:13 +03:00
Neil Lalonde
f8562d8d2f
Version bump to v2.6.5 2021-04-14 11:01:26 -04:00
David Taylor
a19152f3be
SECURITY: Improve theme git import (#12695) 2021-04-14 15:32:33 +01:00
Sam
5b99cb9275
FIX: automatically timeout long running image magick commands (#12670)
Previously certain images may lead to convert / identify to run for unreasonable
amounts of time

This adds a maximum amount of time these commands can run prior to forcing
them to stop
2021-04-12 14:04:37 +03:00
Neil Lalonde
3aa9ae08c2
Version bump to v2.6.4 2021-04-07 12:22:59 -04:00
David Taylor
5dbac4e58e
FIX: Add platforms to stable Gemfile (#12479)
There are a few issues which require us to do this:
 - We install the latest version of bundler on every rebuild. Therefore we're running 2.2.15 everywhere, even for 'stable' clusters
 - Bundler has changed how gem platforms are managed. That meant that on the stable branch we were building libv8 from source via the 'ruby' package, rather than using the precompiled x86_64-linux binary
 - Building the libv8 from source is currently failing

 Together, these things mean that builds of `stable` are currently failing. Each of the above issues should likely be fixed, but this commit provides the quickest route to get things working again. Note that despite the Gemfile.lock update, no gem versions have changed.
2021-03-22 18:54:17 +00:00
Martin Brennan
3ef594b1f1
SECURITY: Fix is_private_ip for RateLimiter to cover all cases (#12464)
The regular expression to detect private IP addresses did not always detect them successfully.
Changed to use ruby's in-built IPAddr.new(ip_address).private? method instead
which does the same thing but covers all cases.
2021-03-22 14:04:55 +10:00
Neil Lalonde
7b283b5f21
Version bump to v2.6.3 2021-03-04 14:08:53 -05:00
jbrw
53f01874bd
FIX: NewPostManager should respect category_group_moderator settings (#12116)
NewPostManager’s `post_needs_approval_in_its_category` method should allow category group moderators to create topics/reply to topics that where they have appropraite permissions.

(ie, if a user has permission to moderate a post, any posts made by them shouldn’t be sent to moderation)
2021-02-24 13:54:54 -05:00
Neil Lalonde
eb9f15a94a
Version bump to v2.6.2 2021-02-18 12:53:47 -05:00
David Taylor
5489a1c4d9
SECURITY: Attach DiscourseConnect (SSO) nonce to current session (#12124) 2021-02-18 10:57:36 +00:00
Arpit Jalan
a4a37b671a FIX: process new invites when existing users are already group members (#11971)
If a list of email addresses is pasted into a group’s Add Members form
that has one or more email addresses of users who already belong to the
group and all other email addresses are for users who do not yet exist
on the forum then no invites were being sent. This commit ensures that
we send invites to new users.
2021-02-05 10:04:35 +05:30
Martin Brennan
946f4b82fa
DEV: Move logic for rate limiting user second factor to one place (#11941)
This moves all the rate limiting for user second factor (based on `params[:second_factor_token]` existing) to the one place, which rate limits by IP and also by username if a user is found.
2021-02-04 09:06:11 +10:00
Robin Ward
98f775506d
SECURITY: Rate limit MFA by login if possible (#11938)
This ensures we rate limit on logins where possible, we also normalize logins for the rate limiters centrally.
2021-02-03 10:32:08 +11:00
Neil Lalonde
d8627cf43f
Version bump to v2.6.1 2021-01-21 14:13:35 -05:00
Arpit Jalan
5130f73bad Bump onebox gem to 2.2.1
- do not show title only oneboxes
- allow oneboxes with title and image
2020-12-24 11:14:21 +05:30
Rafael dos Santos Silva
3a4bd80d8a
FIX: Autoplay videos must always be muted (#11533)
This automatically adds the muted attribute if it's missing in a video
tag.

Co-authored-by: David Taylor <david@taylorhq.com>
2020-12-21 18:09:41 -03:00
Neil Lalonde
d6121249d3
Version bump to v2.6.0 2020-11-30 16:48:47 -05:00
Neil Lalonde
a502a47197
Merge diffs from master 2020-11-30 16:42:54 -05:00
Neil Lalonde
fef0a0c429
Merge master 2020-11-30 16:41:58 -05:00
Sam
225d94d8b8
FIX: correct cdn path (#11324)
This was a typo in a118ec13
2020-11-24 14:17:55 +11:00
Sam
27440ec561
FIX: stop including GlobalPath in default context (#11323)
We do not want these method names to clash, instead encapsulate the helpers
so we do not add methods to Kernel

Correct a but exposed by Ruby 2.7
2020-11-24 14:17:50 +11:00
Neil Lalonde
8a143ebbf8
Version bump to v2.5.5 2020-11-19 10:24:50 -05:00
Dan Ungureanu
8eff1b3a13
FIX: Add dummy themes:update task (#11262) 2020-11-17 11:45:49 +02:00
David Taylor
bacf7966fe
FIX: Remove 4 month limit on IgnoredUser records (#11105)
b8c676e7 added the 'forever' option to the UI, and this is correctly stored in the database. However, we had a hard-coded limit of 4 months in the cleanup job. This commit removes the limit, so ignores can last forever.
2020-11-03 12:31:13 +00:00
Neil Lalonde
77cef20952
Version bump to v2.5.4 2020-10-30 10:28:00 -04:00
Martin Brennan
c7cefb8e08
FIX: Prevent slow bookmark first post reminder at query for topic (#11024)
On forums with a large amount of posts when a user had a bookmark in the topic, PostgreSQL was using an inefficient query plan to fetch the first post of the topic. When running this ActiveRecord query:

```
topic.posts.with_deleted.where(post_number: 1).first
```

The following query plan was produced:

```
 Limit  (cost=0.43..583.49 rows=1 width=891) (actual time=3850.515..3850.515 rows=1 loops=1)
   ->  Index Scan using posts_pkey on posts  (cost=0.43..391231.51 rows=671 width=891) (actual time=3850.514..3850.514
rows=1 loops=1)
         Filter: ((topic_id = 160918) AND (post_number = 1))
         Rows Removed by Filter: 2274520
 Planning time: 0.200 ms
 Execution time: 3850.559 ms
(6 rows)
```

The issue here is the combination of ORDER BY and LIMIT causing the ineficcient Index Scan using posts_pkey on posts to be used. When we correct the AR call to this:

```
topic.posts.with_deleted.find_by(post_number: 1)
```

We end up with a query that still has a LIMIT but no ORDER BY, which in turn creates a much more efficient query plan:

```
Limit  (cost=0.43..1.44 rows=1 width=891) (actual time=0.033..0.034 rows=1 loops=1)
   ->  Index Scan using index_posts_on_topic_id_and_post_number on posts  (cost=0.43..678.82 rows=671 width=891) (actua
l time=0.033..0.033 rows=1 loops=1)
         Index Cond: ((topic_id = 160918) AND (post_number = 1))
 Planning time: 0.167 ms
 Execution time: 0.072 ms
(5 rows)
```

This query plan uses the correct index, `Index Scan using index_posts_on_topic_id_and_post_number on posts`. Note that this is only a problem on forums with a larger amount of posts; tiny forums would not notice the difference. On large forums a query for a topic that takes 1s without a bookmark can take 8-30 seconds, and even end up with 502 errors from nginx.
2020-10-27 16:15:32 +10:00
Neil Lalonde
1829ca605e
Version bump to v2.5.3 2020-10-15 09:50:52 -04:00
Martin Brennan
f6b62919d2
FIX: Confirm new email not sent for staff if email disabled with "non-staff" option (#10794)
See https://meta.discourse.org/t/email-address-change-confirmation-email-not-sent-but-every-other-notification-emails-are/165358

In short: with disable emails set to non-staff, email address change confirmation emails (those sent to the new address) are not sent for staff or admin members.

This was happening because we were looking up the staff user with the to_address of the email, but the to address was the new email address because we are sending a confirm email change email, and thus the user could not be found. We didn't need to do this anyway because we are passing the user into the Email::Sender class anyway.
2020-10-08 14:18:33 +10:00
Roman Rizzi
b9cd5ed62a
SECURITY: Ensure users can see the topic before setting a topic timer. (#10841) 2020-10-06 17:05:45 -03:00
Robin Ward
db8b8742c4 DEV: Add support for api-initializers to reduce boilerplate.
You can now create a file in your plugin/theme in the `api-initializers`
directory which has a simpler template than previous initializers.
Example:

```
// api-initializers/my-plugin.js
import { apiInitializer } from "discourse/lib/api";

export default apiInitializer("0.8", api => {
  console.log("hello world from api initializer!");
});
```
2020-09-30 16:07:28 -04:00
jbrw
c8ed4e9868
DEV: deepMerge and deepEqual functions (#10764) 2020-09-28 13:46:48 -04:00
Neil Lalonde
3e564ff466
Version bump to v2.5.2 2020-09-24 14:30:57 -04:00
Krzysztof Kotlarek
875467c1c5 SECURITY: return error on oversized images 2020-09-14 11:31:48 +10:00
Rafael dos Santos Silva
48d161e3b1 PERF: Add partial index on reviewables for topic view (#10492)
On the topic view route we query for reviewables of each post in the stream,
using a query that filters on two unindexed columns. This results in a Parallel Seq Scan
over all rows, which can take quite some time (~20ms was seen) on forums with lots of flags

After index is added PostgreSQL planner opts for a simple Index Scan and runs in sub 1ms.

Before:

```
                                     QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 Finalize GroupAggregate  (cost=11401.08..11404.87 rows=20 width=28) (actual time=19.209..19.209 rows=1 loops=1)
   Group Key: r.target_id
   ->  Gather Merge  (cost=11401.08..11404.41 rows=26 width=28) (actual time=19.202..20.419 rows=1 loops=1)
         Workers Planned: 2
         Workers Launched: 2
         ->  Partial GroupAggregate  (cost=10401.06..10401.38 rows=13 width=28) (actual time=16.958..16.958 rows=0 loops=3)
               Group Key: r.target_id
               ->  Sort  (cost=10401.06..10401.09 rows=13 width=16) (actual time=16.956..16.956 rows=0 loops=3)
                     Sort Key: r.target_id
                     Sort Method: quicksort  Memory: 25kB
                     Worker 0:  Sort Method: quicksort  Memory: 25kB
                     Worker 1:  Sort Method: quicksort  Memory: 25kB
                     ->  Nested Loop  (cost=0.42..10400.82 rows=13 width=16) (actual time=15.894..16.938 rows=0 loops=3)
                           ->  Parallel Seq Scan on reviewables r  (cost=0.00..10302.47 rows=8 width=12) (actual time=15.882..16.927 rows=0 loops=3)
                                 Filter: (((target_type)::text = 'Post'::text) AND (target_id = ANY ('{7565483,7565563,7565566,7565567,7565568,7565569,7565579,7565580,7565583,7565586,7565588,7565589,7565601,7565602,7565603,7565613,7565620,7565623,7565624,7565626}'::integer[])))
                                 Rows Removed by Filter: 49183
                           ->  Index Scan using index_reviewable_scores_on_reviewable_id on reviewable_scores s  (cost=0.42..12.27 rows=2 width=8) (actual time=0.029..0.030 rows=1 loops=1)
                                 Index Cond: (reviewable_id = r.id)
 Planning Time: 0.318 ms
 Execution Time: 20.470 ms
```

After:
```
                                                                                                          QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
 GroupAggregate  (cost=0.84..342.54 rows=20 width=28) (actual time=0.038..0.038 rows=1 loops=1)
   Group Key: r.target_id
   ->  Nested Loop  (cost=0.84..341.95 rows=31 width=16) (actual time=0.020..0.033 rows=1 loops=1)
         ->  Index Scan using index_reviewables_on_target_id on reviewables r  (cost=0.42..96.07 rows=20 width=12) (actual time=0.013..0.026 rows=1 loops=1)
               Index Cond: (target_id = ANY ('{7565483,7565563,7565566,7565567,7565568,7565569,7565579,7565580,7565583,7565586,7565588,7565589,7565601,7565602,7565603,7565613,7565620,7565623,7565624,7565626}'::integer[]))
         ->  Index Scan using index_reviewable_scores_on_reviewable_id on reviewable_scores s  (cost=0.42..12.27 rows=2 width=8) (actual time=0.005..0.005 rows=1 loops=1)
               Index Cond: (reviewable_id = r.id)
 Planning Time: 0.253 ms
 Execution Time: 0.067 ms
```
2020-09-08 10:49:08 -07:00
Daniel Waterworth
356491aea8 PERF: Don't load all poll_votes for a poll 2020-09-08 10:48:27 -07:00
Guo Xiang Tan
996765562e DEV: Correct use of sanitize_sql_array in TopicQuery. 2020-09-08 10:44:35 +02:00
Guo Xiang Tan
05691b732d DEV: Address review comments for 5ed84d9885. 2020-09-08 10:44:27 +02:00
Guo Xiang Tan
aa1fb1b1b5 SECURITY: Remove indication that a group exists if user can't see it.
Minor security fix but we should not leak any hints that a group exists
even if a user does not have access to the group.
2020-09-08 10:44:09 +02:00
Guo Xiang Tan
1f6e8b642d SECURITY: Don't allow moderators to list PMs of all groups.
* Also return 404 when a user is trying to list PMs of a group that
cannot be accessed by the user.
2020-09-08 10:43:13 +02:00
Neil Lalonde
265eb1c7f9
Version bump to v2.5.1 2020-08-20 14:28:36 -04:00
Jeff Wong
3510534261 FIX: allow plugin pinning to fetch missing commits
Add update for fetching git commits if they do not exist, eg with
clone --depth 1 - only can fetch via git fetch --depth 1 {remote} {ref}
the ref needs to be a full, non-ambiguous reference.
2020-08-13 11:15:19 -07:00
Matt Palmer
e3b1c3a37b FEATURE: Allow the specification of an arbitrary unicorn listen address
Useful if you want to, say, have your unicorn listen on a Unix domain
socket, rather than a TCP port, or you want to be able to bind to a
single address other than 127.0.0.1.
2020-08-05 13:16:31 +05:30
Vinoth Kannan
c661934d41 FIX: rewrite of /my/URL should work on sub directory site too. 2020-08-05 00:56:49 +05:30
Guo Xiang Tan
d4d210eb60
Update rails_failover to 0.5.5. 2020-08-04 11:14:29 +08:00
Guo Xiang Tan
2a0af17a39
FIX: Exclude DELETE methods from invalid request with payload.
Follow-up 105d560177

Our client side code is sending params as part of the request payload so
that is going to be tricky to fix.
2020-08-03 17:05:50 +08:00
Guo Xiang Tan
4342d08edd
SECURITY: 413 for GET, HEAD or DELETE requests with payload. 2020-08-03 15:01:28 +08:00
Guo Xiang Tan
3260865697
DEV: Refactor anonymouse cache spec.
Mainly to properly categorize `Middleware::AnonymousCache` vs `Middleware::AnonymousCache::Helper` specs.
2020-08-03 15:01:19 +08:00
Sam Saffron
a0d4bc47d7 DEV: upgrade mini_racer and libv8
This pushes v8 from Chrome 73 (March 2019) -> 84 (July 14 2020)

Not expecting any user facing changes, but it is super nice to be on latest
v8 :confetti:
2020-07-23 14:31:34 +05:30
Rafael dos Santos Silva
7d30cf707d DEV: Fix search rate limit tests 2020-07-13 10:26:48 -07:00
Rafael dos Santos Silva
6aad9cd0c8 FEATURE: Add global rate limit for anon searches (#10208) 2020-07-13 10:26:42 -07:00
Martin Brennan
3f7658cc6e
SECURITY: Add content-disposition: attachment for SVG uploads
* strip out the href and xlink:href attributes from use element that
  are _not_ anchors in svgs which can be used for XSS
* adding the content-disposition: attachment ensures that
  uploaded SVGs cannot be opened and executed using the XSS exploit.
  svgs embedded using an img tag do not suffer from the same exploit
2020-07-09 13:54:45 +10:00
Jeff Wong
271d6319ce Support plugin and Theme compatibility version manifests (#9995)
Adds a new rake task `plugin:checkout_compatible_all` and
`plugin:checkout_compatible[plugin-name]` that check out compatible plugin
versions.

Supports a .discourse-compatibility file in the root of plugins and themes that
list out a plugin's compatibility with certain discourse versions:

eg: .discourse-compatibility
```
2.5.0.beta6: some-git-hash
2.4.4.beta4: some-git-tag
2.2.0: git-reference
```

This ensures older Discourse installs are able to find and install older
versions of plugins without intervention, through the manifest only.

It iterates through the versions in descending order. If the current Discourse
version matches an item in the manifest, it checks out the listed plugin target.
If the Discourse version is greater than an item in the manifest, it checks out
the next highest version listed in the manifest.

If no versions match, it makes no change.
2020-07-08 15:45:47 -07:00
Régis Hanol
c33847b30d FIX: uploading an existing image as a site setting
The previous fix (f43c0a5d85) wasn't working for images that were already uploaded.
The "metadata" (eg. 'for_*' and 'secure' attributes) were not added to existing uploads.

Also used 'Upload.get_from_url' is the admin/site_setting controller to properly retrieve
an upload from its URL.

Fixed the Upload::URL_REGEX to use the \h (hexadecimal) for the SHA

Follow-up-to: f43c0a5d85
2020-07-03 19:19:14 +02:00
Régis Hanol
08407905ba FIX: uploading an image as a site setting
When uploading an image as a site setting, we need to return the "raw" URL, otherwise
when saving the site setting, the upload won't be looked up properly.

Follow-up-to: f11363d446
2020-07-03 14:59:15 +02:00
Osama Sayegh
4a10350496 FIX: Negative limit values shouldn't cause error 500 (#10162) 2020-07-02 15:15:25 -04:00
Guo Xiang Tan
e94907eea4 FIX: Delete related search data when record has been deleted. 2020-07-02 15:14:17 -04:00
Vinoth Kannan
260bb6f073 FIX: return cdn url for uploads if available.
Currently it is displaying non-cdn urls in the composer preview.
2020-07-02 15:14:01 -04:00
Robin Ward
3a14bd6b14 FIX: Support root paths that omit the trailing slash and have QPs 2020-07-02 15:13:44 -04:00
Robin Ward
81ce3c8e50 FIX: Search was not multisite aware 2020-07-02 15:13:32 -04:00
Sam Saffron
7bfbecad7e PERF: cache all metadata for 60 seconds
Clients tend to request webmanifests and such very often.

Keep the data cached for 60 seconds so it is not requested aggresively.
2020-07-02 15:12:59 -04:00
Gerhard Schlager
f69e5a4d7e FIX: Sometimes not all output of psql was logged during restores
There was a race condition which could prevent Discourse from logging the last couple of lines of output from psql.
2020-07-02 15:12:44 -04:00
Sam Saffron
43a41f3928 FIX: emoji_autocomplete_min_chars failing when not 0
autocomplete resolving to [] was causing it to stop working.
Instead we have a special const (SKIP) which ensures it will
continue to be evaluated and only this instance is skipped.
2020-07-02 15:12:30 -04:00
Mark VanLandingham
67cc6731c6 FIX: update theme fields when updating from ThemesInstallTask (#10143) 2020-07-02 15:12:15 -04:00
Régis Hanol
3de1cf128c FIX: identify slug-less topic urls everywhere
In 91c89df6, I fixed the onebox to support local topics with a slug-less URL.
This commit fixes all the other spots (search, topic links and user badges) where we look up for a local topic.

Follow-up-to: 91c89df6
2020-07-02 15:11:36 -04:00
Dan Ungureanu
1f6f1604c9 FIX: Serialize an empty array if no suggested topics exist (#10134)
It used to return nil, which was ambiguous (empty vs absent
result).
2020-07-02 15:10:52 -04:00
Joshua Rosenfeld
8fbc41d993 FIX: Broken specs
`/u/` is no longer in robots.txt, so don't test for it
2020-07-02 15:09:50 -04:00
Joshua Rosenfeld
417bdcb53a FIX: Remove paths from robots.txt in favor of noindex header
Google no longer supports the use of robots.txt to block indexing.
See https://support.google.com/webmasters/answer/6062608 and
https://support.google.com/webmasters/answer/93710

Previous commits have added the `noindex` header to appropriate pages,
now we need to remove the paths from robots.txt so the pages can be
crawled.

Follow up to:
13f229808a
b6765aac4b
676be3a853
07b728c5e5
c94e6a9a66
2020-07-02 15:09:40 -04:00
Régis Hanol
d156b7749d FIX: match discobot triggers on cooked version
In French, the help trigger has a raw content of "afficher l'aider" which is then cooked into "afficher l’aide" (note the different quote character).
Since we were checking the raw content of the trigger against the cooked version of the post, this trigger never worked in French.

This changes so that we cook the trigger before checking in against the cooked version of the post.

DEV: new 'discobot_username' method that is used everywhere instead of 'discobot_user.username' / 'discobot_user.username_lower'
2020-07-02 15:09:22 -04:00
Sam Saffron
17182edab2 FIX: invalid urls should not break store.has_been_uploaded?
Breaking this method has wide ramification including breaking
search indexing.
2020-07-02 15:09:10 -04:00
Sam Saffron
ae520b62e4 FEATURE: allow disabling of extra term injection in search
There is a feature in search where we take over from the tokenizer
in postgres and attempt to inject more words into search.

So for example: sam.i.am will inject the words i and am.

This is not ideal cause there are many edge cases and this can
cause extreme index bloat.

This is an opening move commit to make it configurable, over the
next few weeks we will evaluate and decide if we disable this by
default or simply remove.
2020-07-02 15:08:53 -04:00
Sam Saffron
5f5dd9ea67 PERF: stop adding more topics to search when not needed
The logic of adding additional search results does not seem to be
needed anymore.

It appears to be a relic of an old implementation.

This saves an entire search query for every search made.
2020-07-02 15:08:33 -04:00
Guo Xiang Tan
f10f87cc68 FIX: Avoid marking notifications as seen in readonly mode. 2020-07-02 15:08:13 -04:00
Roman Rizzi
1b17482eab FIX: Uploads cannot be mapped due to the cook-text's element attr being null (#10136) 2020-06-30 12:07:50 -03:00
David Taylor
19db1a7d2a
FIX: Correct version comparison logic when comparing stable to beta (#10135)
* FIX: Correct version comparison logic when comparing stable to beta

For example, version 1.3.0 should be considered higher than 1.3.0.beta3. So `Discourse.has_needed_version?('1.3.0', '1.3.0.beta3')` should return true

* Switch to use Gem::Version to compare versions
2020-06-30 09:37:01 +01:00
tshenry
c271b0c394
FIX: published-page-header should be a sibling to published-page-body not a parent (#10126) 2020-06-25 14:59:33 -07:00
Neil Lalonde
6a42acbfb7
Version bump to v2.5.0 2020-06-24 13:56:53 -04:00
Neil Lalonde
eb10109c99
Merge diffs from master 2020-06-24 13:48:37 -04:00
Neil Lalonde
607d00f780
Merge master 2020-06-24 13:47:36 -04:00
Neil Lalonde
53c7d0200a
Version bump to v2.4.5 2020-06-01 14:05:48 -04:00
Jeff Wong
b6ff3b6a26 SECURITY: make find topic by slug adhere to SiteSetting.detailed_404 (#9898) 2020-05-28 13:54:10 -07:00
Blake Erickson
745d1de40c SECURITY: Use FinalDestination for topic embeds 2020-05-27 09:31:15 -06:00
Neil Lalonde
fe275c97c1
Version bump to v2.4.4 2020-05-26 10:31:32 -04:00
Blake Erickson
7f6a321fec SECURITY: ensure embed_url contains valid http(s) uri 2020-05-22 15:15:44 -06:00
Robin Ward
a55d5bd1b0 SECURITY: ERB execution in custom Email Style 2020-05-21 14:49:06 -04:00
Neil Lalonde
ec33d7e237
Version bump to v2.4.3 2020-05-04 11:31:32 -04:00
Robin Ward
7cc7baf378 SECURITY: Update onebox to add rel="noopener" 2020-04-29 10:59:06 -04:00
Neil Lalonde
10e11fd5d8
Version bump to v2.4.2 2020-04-22 10:15:37 -04:00
Blake Erickson
6b20d52338 FIX: Staged users getting user_linked and user_quoted emails
This fix ensures that if a staged user is linked to or quoted they won't
be emailed about it.

A staged user could email into a category, and another user could quote
them inside of a completely different category and we don't want a
staged user to receive an email for this.

Bug report:

https://meta.discourse.org/t/-/145202/9
2020-03-31 21:00:56 -06:00
Jeff Wong
45296a8fe9 FIX: backport reviewable topic claim not being shown correctly 2020-03-30 15:23:16 -07:00
Jeff Wong
385c3fe789 FIX: claiming topics for the review queue 2020-03-30 15:16:47 -07:00
Jeff Wong
7817d8b2ff FEATURE: Unassign the review queue topic when a flag is handled 2020-03-25 14:17:08 -07:00
Bianca Nenciu
fe15082d44 SECURITY: Ensure user can see group and group members 2020-03-24 12:23:11 +02:00
Jeff Wong
0e553f1fd1 FIX: correctly remove authentication_data cookie on oauth login flow (#9238)
Additionally correctly handle cookie path for authentication_data

There were two bugs that exposed an interesting case where two discourse
instances hosted across two subfolder installs in the same domain
with oauth may clash and cause strange redirection on first login:

Log in to example.com/forum1. authentication_data cookie is set with path /
On the first redirection, the current authentication_data cookie is not unset.
Log in to example.com/forum2. In this case, the authentication_data cookie
is already set from forum1 - the initial page load will incorrectly redirect
the user to the redirect URL from the already-stored cookie, to /forum1.

This removes this issue by:
* Setting the cookie for the correct path, and not having it on root
* Correctly removing the cookie on first login
2020-03-23 16:01:39 -07:00
Jeff Wong
e0f711960b FIX: consistency to show mute/ignore menu in user profile
Show the mute/ignore menu for another user even when the current user
cannot message them.
2020-03-23 16:01:39 -07:00
Jeff Wong
111fa7e277 FEATURE: prevent accidental canceling when drafting penalties (#9129)
Pop up a confirmation box when there is input. This prevents accidental closing
of the dialog boxes due to clicking outside.

This adds a development hook on modals in the form of a `beforeClose`
function. Modal windows can abort the close if the funtion returns false.

Additionally fixing a few issues with loop and state on the modal popups:

Escape key with bootbox is keyup.
Updating modal to close on keyup as well so escape key is working.
Fixes an issue where pressing esc will loop immediately back to the modal by:
keydown -> bootbox -> keyup -> acts as "cancel", restores modal

Needs a next call to reopenModal otherwise, keyup is handled again by the modal.
Fixes an issue where pressing esc will loop immediately back to the confirm:
esc keyup will be handled and bubble immediately back to the modal.

Additionally, only handle key events when the #discourse-modal is visible.
This resolves issues where escape or enter events were being handled by
a hidden modal window.
2020-03-23 16:01:39 -07:00
David Taylor
4e178d5c0d
SECURITY: Respect topic permissions when loading draft metadata
Co-authored-by: Sam Saffron <sam.saffron@gmail.com>
2020-03-23 11:54:36 +00:00
David Taylor
0e3dfd2925
DEV: Load plugin stylesheets before theme stylesheets (#9240)
This is a more logical order, since themes are more lightweight than plugins, and are often used to augment plugin styles
2020-03-19 19:24:06 +00:00
Martin Brennan
4eb4293e66 FIX: Ensure show_short URLs handle secure uploads using multisite (#9212)
Meta report: https://meta.discourse.org/t/short-url-secure-uploads-s3/144224
* if the show_short route is hit for an upload that is
  secure, we redirect to the secure presigned URL. however
  this was not taking into account multisite so the db name
  was left off the path which broke the presigned URL
* we now use the correct url_for method if we know the
  upload (like in the show_short case) which takes into
  account multisite
2020-03-17 11:41:51 +10:00
Joffrey JAFFEUX
c4cd864c26 FIX: throttles topic tracking shortcut and enforces topic id (#9159) 2020-03-13 12:03:55 +01:00
Joffrey JAFFEUX
b4b0443d63 FIX: ensures pinned-options header is showing correct state (#9156) 2020-03-12 07:41:17 +01:00
Robin Ward
f8c31eb1e0 Let's not log the username/password
This could easily be seen by someone who shouldn't.
2020-03-11 12:54:19 -04:00
Sam Saffron
c738d31809
FIX: last ip address could point at wrong ip
Due to unicorn env object recycling request.ip could point at the wrong
ip address by the time defer block is called. This usually would happen
under load.

This also avoids keeping the entire request object as referenced by the
closure.
2020-03-11 17:43:44 +11:00
Neil Lalonde
ea73880146
Version bump to v2.4.1 2020-03-05 12:28:17 -05:00
Gerhard Schlager
766665a287
FIX: Restoring with disable_emails: false didn't work anymore 2020-03-05 11:47:35 -05:00
Martin Brennan
f0072dd897
FIX: Stop infinite lookup-urls issue for video/audio on page (#9096)
Meta report: https://meta.discourse.org/t/excessive-requests-to-uploads-lookup-urls-leading-to-429-response/143119

* The data-orig-src attribute was not being removed from cooked
video and audio so the composer was infinitely trying to get the
URLs for them, which would never resolve to anything
* Also the code that retrieved the short URL was unscoped, and was
getting everything on the page. if running from the composer we
now scope to the preview window
* Also fixed a minor issue where the element href for the video
and audio tags was not being set when the short URL was found
2020-03-05 11:47:14 -05:00
Joffrey JAFFEUX
d5ab4776cd
FIX: prevents click on sk header to bubble (#9084) 2020-03-05 11:46:55 -05:00
Gerhard Schlager
55a49d8494
FIX: Google Groups scraper failed to login 2020-03-05 11:46:36 -05:00
Sam Saffron
980d2ed052
PERF: improve performance of category topic list
In some cases CTE caused pathologically bad query plans.
This optimises it so query runs by itself and caches for lifetime
of the topic query object.

This lightweight caching is done cause topic query will often
execute two queries (one for pinned and one for non pinned)
2020-03-05 11:46:20 -05:00
Dan Ungureanu
5f88b86ac9
FIX: Sync preload key format for category topic lists
The server and client used two different formats for preload keys. The
server was using 'topic_list_c/SLUG/l/latest', but the client was using
'topic_list_c/SLUG/ID/l/latest'.

This commit is an addition to 374534f00e.
2020-03-05 11:46:02 -05:00
Dan Ungureanu
4bb966aae6
DEV: Fix build
Follow up to 60184a290c.
2020-03-05 11:45:45 -05:00
Joffrey JAFFEUX
2cc533e26e
FIX: prevents loading to show during debouncing (#9060)
This will also fix a bug in IE11 where click event would not be triggered on row
2020-03-05 11:45:19 -05:00
Joffrey JAFFEUX
751708ba0c
FIX: prevents row click event to be caught by filter input event (#9059)
This was causing some dropdowns to not work under IE11
2020-03-05 11:44:54 -05:00
David Taylor
b8e4b5f884
FIX: Polyfill Promise for IE11 (#9057)
Co-authored-by: Joffrey JAFFEUX <j.jaffeux@gmail.com>
2020-03-05 11:44:33 -05:00
Robin Ward
c7634d56f6 SECURITY: Add more restrictions on invite emails
They could be filtered and returned in some circumstances where they
shouldn't have been.
2020-03-05 09:55:54 -05:00
Robin Ward
20a8a2f396 SECURITY: Ensure the invite JSON API matches the UX
Anonymous users could query the invite json and see counts and
summaries which is not allowed in the UX of Discourse.

This commit has those endpoints return a 403 unless the user is
allowed to invite.
2020-03-05 09:55:45 -05:00
Joffrey JAFFEUX
2246fe8015 FIX: allows to select the action when agreeing with penalty (#9099)
Note this commit also fixes an issue where the edit post actions was trying to focus the edit textarea, but was using jquery functions on a DOM node.

scrollTo is not available on IE11 but that shouldn't cause much trouble.
2020-03-04 10:32:20 -05:00
Mark VanLandingham
737e8bdb2c FIX: Prettier on iframed-html component (#9062) 2020-02-27 11:57:18 -06:00
Mark VanLandingham
df70b9118e Merge pull request from GHSA-vw39-6w7q-gfx5
Co-authored-by: Robin Ward <robin.ward@gmail.com>
2020-02-27 11:57:10 -06:00
Neil Lalonde
76b9be3f19 Version bump to v2.4.0 2020-02-26 16:46:06 -05:00
Neil Lalonde
254d410d4e Merge branch 'master' into stable 2020-02-25 17:32:08 -05:00
Neil Lalonde
4d611dcaed Merge diffs from master 2020-02-25 17:23:37 -05:00
Neil Lalonde
52c10848bc Merge master 2020-02-25 17:21:37 -05:00
Neil Lalonde
632ef306e2 Version bump to v2.3.10 2020-02-13 16:26:48 -05:00
David Taylor
4b56345672 DEV: Bump omniauth-github from 1.3.0 to 1.4.0 (#8924)
This switches the github API access to use header-based authentication, rather than the deprecated parameter-based method
2020-02-11 09:47:30 +00:00
Sam Saffron
7e39f779b4 FEATURE: support MaxMind DB downloads using a license key
MaxMind now requires an account with a license key to download files.

Discourse admins can register for such an account at:

https://www.maxmind.com/en/geolite2/signup

License key generation is available in the profile section.

Once registered you can set the license key using `DISCOURSE_MAXMIND_LICENSE_KEY`

This amends it so we unconditionally skip MaxMind DB downloads if no license key exists.
2020-02-05 16:40:04 +11:00
Roman Rizzi
b231be8865 FIX: Ensure sourcemap's source is correct. Uses the full assets path this time. (#8774)
Cherry-picked from 8eb2147f1f
2020-01-24 15:54:21 -03:00
Neil Lalonde
9298132c73 Version bump to v2.3.9 2020-01-21 15:46:33 -05:00
Roman Rizzi
733143cba3 SECURITY: Do not create a notification if a staged user post gets quoted/linked inside a restricted category 2020-01-16 15:37:03 -03:00
Régis Hanol
65831f4d3e SECURITY: use strict JSON parsing when parsing backup metadata 2020-01-15 22:05:38 +01:00
Rafael dos Santos Silva
ad7a13921f
FIX: Use cached MaxMind DB for longer
Don't try to update the IP database as it's gone.

This allows users to rebuild Discourse while we work on a proper
fix / alternative database.
2019-12-31 13:07:43 -03:00
Robin Ward
a6701d8710 FIX: Gemfile bundler was breaking build
We update bundler in app.yml and the version received was too
new for our Gemfile.lock
2019-12-26 14:40:27 -05:00
Robin Ward
6e88dde635 FIX: Build was broken due to missing file
It seems a file was in the base image but .gitignored, so the
stable branch got into a weird state.
2019-12-26 14:40:13 -05:00
Neil Lalonde
d4e0eb63a2 Version bump to v2.3.8 2019-12-19 14:22:00 -05:00
David Taylor
ff4a6a37de SECURITY: Correct permission check when revoking user API keys 2019-12-17 11:07:36 +00:00
Krzysztof Kotlarek
1c49875048 SECURITY: vulnerability in WildcardUrlChecker 2019-12-13 09:55:43 -05:00
Krzysztof Kotlarek
e1e571d32c SECURITY: upgrade rack-mini-profiler to avoid possible XSS (#8537) 2019-12-12 13:23:09 +11:00
Dan Ungureanu
554b0f366d
SECURITY: Ensure only image uploads can be inlined
This prevents malicious files (for example special crafted XMLs) to be
used in XSS attacks.
2019-12-11 17:08:58 +02:00
Dan Ungureanu
43ddb6b36d
SECURITY: Remove event handlers from SVG files 2019-12-11 17:08:57 +02:00
Neil Lalonde
5b17584adb Version bump to v2.3.7 2019-12-05 13:11:05 -05:00
Joffrey JAFFEUX
5cb00d5528 DEV: s/\$redis/Discourse\.redis
With manual merge conflicts
2019-12-03 14:26:57 +01:00
Sam Saffron
14db879a31 DEV: Implement a faster Discourse.cache
This is a bottom up rewrite of Discourse cache to support faster performance
and a limited surface area.

ActiveSupport::Cache::Store accepts many options we do not use, this partial
implementation only picks the bits out that we do use and want to support.

Additionally params are named which avoids typos such as "expires_at" vs "expires_in"

This also moves a few spots in Discourse to use Discourse.cache over setex
Performance of setex and Discourse.cache.write is similar.
2019-12-03 14:03:30 +01:00
Sam Saffron
ef791a5b1f DEV: use Discourse.cache over Rails.cache
With manual merge
2019-12-03 14:03:21 +01:00
Neil Lalonde
69983297ed Version bump to v2.3.6 2019-11-06 12:46:03 -05:00
David Taylor
914e50db49 DEV: Update users controller spec following user_search update 2019-11-06 17:32:10 +00:00
Robin Ward
5f01814397 FIX: Handle nil case for avatar, just in case 2019-10-28 11:30:34 -03:00
Robin Ward
069d358c80 FIX: Allow avatar downloads to follow redirects 2019-10-28 11:30:21 -03:00
David Taylor
c38c37bcc3 SECURITY: Check permissions when autocompleting mentions 2019-10-28 12:20:26 +00:00
Robin Ward
afea20953f FIX: Broken certificates 2019-10-24 14:13:27 -03:00
Roman Rizzi
3a73f29928 FIX: Rate limit and hijack certificate generation. (#8215)
To eliminate a DDOS attack vector, we're taking the following measures:

The endpoint will be rate-limited to 3 requests every 60 seconds (per user).
A 24 hours max-age cache header is sent with the response.
The route will be hijacked to generate the certificate in the background.
2019-10-22 15:39:58 -03:00
Krzysztof Kotlarek
5bcc1c1cd5 FIX: Narrative Bot certificates are ERB templates (#8174)
There are at least two ways of rendering templates outside of the controller. The first one is Rails way enabled with Rails 5 https://evilmartians.com/chronicles/new-feature-in-rails-5-render-views-outside-of-actions
The downside of this method is that all variables need to be passed as params (I could find a way to pass the whole context)

Another way is to use instance_eval described in Erubi documentation
https://github.com/jeremyevans/erubi#usage - it works perfectly fine, however, I didn't feel very confident about using eval unless necessary.

An additional benefit of using `ApplicationController.render` is that if Rails would change the ERB engine in the future, this code should still work.

If you want to test it on your local, you need to be signed in and then that two URLs are generating certificates:
http://localhost:3000/discobot/certificate.svg?date=Oct+07+2019&type=standard&user_id=1
http://localhost:3000/discobot/certificate.svg?date=Oct+07+2019&type=advanced&user_id=1

Dev: https://dev.discourse.org/t/discourse-narrative-bot-should-not-be-storing-giant-strings/17130
2019-10-22 15:39:42 -03:00
Neil Lalonde
76f6ee501f Version bump to v2.3.5 2019-10-10 11:44:33 -04:00
Roman Rizzi
e4570ffb78 DEV: Bump uglifyjs (#7834)
* Rewrite uglifyjs command to work with 3.x

* Use ES5 syntax in plain JS files

* Use the older command if uglifyJS V2.x is installed
2019-10-09 10:36:15 -03:00
Sam Saffron
8f001bdb1b SECURITY: mini profiler enabled incorrectly for admins
We expect mini profiler only to show up on accounts that are flagged as
developer accounts.

Unfortunately there was a bypass on any controllers that mix in ApplicationHelper
2019-10-09 12:50:58 +11:00
David Taylor
68fc799380 DEV: Allow specifying button class in reviewable action definitions (#8093)
This avoids the need for using `@extend` in SCSS, which can be problematic in plugins

For context, see https://review.discourse.org/t/fix-make-compatible-with-debundled-plugin-css-assets-feature/5297/7
2019-10-08 15:06:15 -03:00
Sam Saffron
67e8fbc480 FIX: change focus when application resumes in android
Per new lifecycle https://developers.google.com/web/updates/2018/07/page-lifecycle-api

On Android and latest Chrome when an app transitions from "frozen" to
active the new "resume" event fires with no accompanying "visibilitychange"
event.

This means that often background tabs may be stuck thinking that discourse
has no focus when, indeed, it has.

This leads to cases where no posts are marked read anymore.
2019-10-08 00:04:54 +02:00
Neil Lalonde
3e73c0a34d Version bump to v2.3.4 2019-10-01 17:43:25 -04:00
romanrizzi
ba3dbcc117 Spec should not depend on aliases 2019-10-01 18:35:41 -03:00
Robin Ward
cd20d0fdfd SECURITY: Don't allow base_uri as embeddable host if none exist 2019-10-01 17:58:39 +02:00
Sam Saffron
fd0bb34001 SECURITY: update rack-mini-profiler to latest to correct XSS
This corrects an XSS in ?pp=help.

Also removes the jQuery dependency from rack-mini-profiler and restricts
memory sensitive profiling methods development only.
2019-10-01 16:56:51 +10:00
Penar Musaraj
6e04120e71 SECURITY: XSS when oneboxing user profile location field
The XSS here is only possible if CSP is disabled. Low impact since CSP is enabled by default in SiteSettings.
2019-09-17 16:36:53 -04:00
Roman Rizzi
fd1a2a4c07 FIX: Improve protection against problematic usernames (#8097) 2019-09-13 15:52:05 -03:00
Penar Musaraj
051462cbe2 FIX: IE grid layout issue on user's own activity page 2019-09-12 11:15:47 -04:00
Nick Quaranto
21c11c2bb2 Use Discourse.getURL for /clicks/track so clicks can be tracked on relative URLs (#8079) 2019-09-09 23:17:43 -07:00
Régis Hanol
39a427efce DEV: plugin API to register User custom field types 2019-09-06 12:16:59 +02:00
Roman Rizzi
24fc0aba9b FIX: :reject_user_delete action can only be handled by ReviewableUser (#8068) 2019-09-05 11:44:16 -03:00
Jeff Wong
b72dbb0be0 FEATURE: add before-topic-progress plugin outlet 2019-09-04 11:29:05 -07:00
Neil Lalonde
046b6300d1 Version bump to v2.3.3 2019-09-04 10:44:22 -04:00
Roman Rizzi
52fdc1468d Feature/Fix: Flagged posts user notifications (#8041)
* FIX: User should get notified when a post is deleted

* FEATURE: Notify posters when restoring flagged posts

* Fix typo

Co-Authored-By: Régis Hanol <regis@hanol.fr>

* Improve tests
2019-09-02 15:22:03 -03:00
David Taylor
51b7f4d900 FIX: When activating via omniauth, create tokens after password reset
Resetting a password invalidates all email tokens, so we need to create the tokens after the password reset.
2019-08-28 14:50:07 +01:00
David Taylor
3b9e8a0849 FIX: When activating a user, ensure the change is reflected immediately
When activating a user via an external provider, this would cause the "this account is not activated" message to show on the first attempt, even though the account had been activated correctly.
2019-08-28 14:09:03 +01:00
David Taylor
f80f8a34c0 SECURITY: Reset password when activating an account via auth provider
Followup to d693b4e35fe0e58c5578eae4a56c06dff4756ba2
2019-08-28 14:08:55 +01:00
Sam Saffron
a3d42e2c52 FIX: add_to_serializer not correctly accounting for inheritance chains
This is a very long standing bug we had, if a plugin attempted to amend a
serializer core was not "correcting" the situation for all descendant classes
this often only showed up in production cause production eager loads serializers
prior to plugins amending them.

This is a critical fix for various plugins
2019-08-27 18:23:32 +10:00
Sam Saffron
6477531098 SECURITY: add rate limiting to anon JS error reporting
This adds a 1 minute rate limit to all JS error reporting per IP. Previously
we would only use the global rate limit.

This also introduces DISCOURSE_ENABLE_JS_ERROR_REPORTING, if it is set to
false then no JS error reporting will be allowed on the site.
2019-08-20 11:31:58 +10:00
Arpit Jalan
aea541d037 SECURITY: don't reveal category details to users that do not have access 2019-08-19 12:51:15 +05:30
David Taylor
d237da16c5 SECURITY: Restrict message-bus access on login_required sites 2019-08-14 10:11:28 +01:00
Gerhard Schlager
ab3e18090f FIX: Disallow user self-delete when user posted in PMs
All posts created by the user are counted unless they are deleted,
belong to a PM sent between a non-human user and the user or belong
to a PM created by the user which doesn't have any other recipients.

It also makes the guardian prevent self-deletes when SSO is enabled.
2019-08-10 12:06:40 +02:00
Roman Rizzi
0be47023d4 FIX: Use unescaped title as combo-box id (#7979) 2019-08-08 12:52:34 -03:00
David Taylor
b1d2e4daf3 FIX: Composer preview on IE11 (#7970)
Add the Array.from polyfill for IE11. This is required to support the transpiled ES6 spread syntex generated by babel: https://babeljs.io/docs/en/caveats/
2019-08-05 14:44:13 +01:00
Sam Saffron
c587df7e2a Revert "FEATURE: add Noindex to robots.txt for disallowed routes"
This reverts commit d84256a876.

This is not supported by Google and causes robots.txt to be flagged as
invalid

Removing Noindex
2019-07-30 11:37:00 +10:00
David Taylor
85cdf213e1 FIX: Hide live-loaded posts from ignored users 2019-07-27 14:00:34 +01:00
David Taylor
e9c0fb0621 SECURITY: Sanitize email id for use as mutex key 2019-07-24 13:51:08 +01:00
David Taylor
c4ff66e1a5 DEV: Correct merge conflicts for 9cfe3f99 2019-07-24 13:31:16 +01:00
David Taylor
9cfe3f9948 SECURITY: Add confirmation screen when connecting associated accounts 2019-07-24 13:29:59 +01:00
Gerhard Schlager
90a1aa5536 SECURITY: Validate backup chunk identifier 2019-07-22 08:44:38 +02:00
Neil Lalonde
af192ff9d5 Version bump to v2.3.2 2019-07-15 10:00:45 -04:00
Guo Xiang Tan
3663ef6394 Fix the build.
Follow up to 4b0cf7f6dd.
2019-07-15 16:42:58 +08:00
Guo Xiang Tan
477bacb3ae SECURITY: XSS when displaying watched words in admin panel.
The XSS here is only possible if CSP is disabled. Low impact since CSP
is enabled by default in SiteSettings.
2019-07-15 10:58:52 +08:00
Robin Ward
fe8bd92f71 SECURITY: SQL injection with default categories
This is a low severity security fix because it requires a logged in
admin user to update a site setting via the API directly to an invalid
value.

The fix adds validation for the affected site settings, as well as a
secondary fix to prevent injection in the event of bad data somehow
already exists.
2019-07-11 13:53:12 -04:00
Robin Ward
2f91f88d06 SECURITY: Upgrade lodash
There is a security hole in lodash with prototype pollution. It's not
clear if Discourse is affected but to be on the safe side we will
upgrade right away.

Note that the front end Discourse does not appear to use `defaultsDeep`
in our custom build and should be protected.
2019-07-11 10:51:44 -04:00
Robin Ward
d1c12539dd SECURITY: XSS with title selector on preferences page
Note this is very low severity as the group needs to be created with a
default title that contains HTML, and group creation is restricted to
staff members right now.
2019-07-09 17:35:26 -04:00
Robin Ward
4fd470e63d SECURITY: Strip HTML from invite emails
We also strip new lines from the emails because it ruins the markdown
formatting which expects a one line message.
2019-07-05 14:58:46 -04:00
Jeff Wong
a7a7afdb27 FIX: iterate when clearing watched words cache 2019-07-04 08:59:01 -07:00
romanrizzi
2a7d270fd6 Revert "FIX: remove misplaced save button"
This reverts commit f1381a274b.
2019-07-03 10:58:33 -03:00
romanrizzi
f1381a274b FIX: remove misplaced save button 2019-07-03 10:47:54 -03:00
romanrizzi
34d548dbd3 FIX: Remove misplaced outlet 2019-07-03 10:47:43 -03:00
Arpit Jalan
867eebb55e FIX: creating new badge is failing on empty SQL query (#7837) 2019-07-02 15:17:32 +05:30
Gerhard Schlager
b549cab2ad FIX: Don't send notification email when user isn't allowed to see topic 2019-07-02 09:05:36 +10:00
Gerhard Schlager
5b91182985 DEV: Respond with error 400 to uploads requested via XHR
follow-up to 13f38055
2019-06-27 11:30:05 +02:00
Sam Saffron
467e03a2ec DEV: lint file
We no longer need that isAppleDevice require
2019-06-27 11:29:51 +02:00
Joffrey JAFFEUX
a91881280d FIX: closes search-menu on escape (#7804) 2019-06-27 09:34:34 +02:00
Joffrey JAFFEUX
690fb5c4fb FIX: prevents failure when TL was mutated on internal object (#7808) 2019-06-27 09:34:31 +02:00
Gerhard Schlager
9c8aa0a906 SECURITY: XSS in routes
Co-authored-by: Guo Xiang Tan <tgx_world@hotmail.com>
Co-authored-by: David Taylor <david@taylorhq.com>
2019-06-26 16:45:33 +02:00
Bianca Nenciu
3503271959 SECURITY: Escape email text for posts containing [details]. 2019-06-26 16:45:25 +02:00
Neil Lalonde
2c26998f86 Version bump to v2.3.1 2019-06-25 12:26:20 -04:00
Neil Lalonde
6411810630 Update translations 2019-06-25 11:50:50 -04:00
Sam Saffron
0fa02274c2 DEV: bump version on mini_scheduler
This corrects a catastrophic state that can ensue if redis becomes readonly

It also adds support for multiple queues and minor cleanup
2019-06-25 11:50:19 -04:00
Penar Musaraj
8b963bce37 FIX: Do not refresh all settings on save for all settings, limit to only a few
- Followup to 0e303c7f5d

- Automatically reloads site settings after saving only for the logo, logo_small and large_icon settings.
2019-06-25 11:49:09 -04:00
Penar Musaraj
e1822034dc FIX: use correct name for selectable_avatars_enabled site setting 2019-06-25 11:48:56 -04:00
Maja Komel
faf059e018 FIX: remove temporary hack for fixed iOS bug (#7773)
A bug where input focus is displaced on modals was fixed in iOS 11.3 update. This hack was causing problems on topic page since hiding main-outlet results in lost read position after opening and closing a modal.
2019-06-25 11:48:42 -04:00
Joffrey JAFFEUX
f2d5cde24c FIX: category-chooser search should be scoped to category (#7794) 2019-06-24 11:31:41 +02:00
Neil Lalonde
0bcb62fc2d Version bump to v2.3.0 2019-06-17 20:47:22 -04:00
Neil Lalonde
04be572a92 Merge diffs from master 2019-06-17 20:07:19 -04:00
Neil Lalonde
a4308fdd43 Merge master 2019-06-17 20:04:04 -04:00
David Taylor
40cbcc7720 SECURITY: Add confirmation screen when logging in via email link 2019-06-17 18:20:48 +01:00
Neil Lalonde
809a544786 Version bump to v2.2.6 2019-06-10 11:47:21 -04:00
Penar Musaraj
39bececaaf SECURITY: Bump Handlebars to version 4.1.2
WS-2019-0064: Versions of handlebars prior to 4.0.14 are vulnerable to Prototype Pollution. Templates may alter an Objects prototype, thus allowing an attacker to execute arbitrary code on the server.
2019-06-05 14:57:50 -04:00
Rafael dos Santos Silva
c294ff3609 Version bump to v2.2.5 2019-05-08 18:30:55 -03:00
Rafael dos Santos Silva
99dd426b12 FIX: We need a newer mini_racer for ruby 2.6.3
This is necessary because the bumped ruby version (which happens
in the discourse_docker repo) doesn't install mini_racer < 0.2.4
2019-05-08 18:08:28 -03:00
Dan Ungureanu
2a8118fb44
SECURITY: Fix tab nabbing. 2019-04-25 00:34:59 +03:00
Gerhard Schlager
b264661fe2 SECURITY: Update nokogiri 2019-04-24 16:37:47 +02:00
Joffrey JAFFEUX
922d93c1d4 SECURITY: jquery CVE-2019-11358 2019-04-24 16:31:26 +02:00
Sam Saffron
e143cc1843 FEATURE: enable NGINX brotli support unconditionally
Previously we would rely on enable brotli in the web template to turn this
on, going forward this is default on
2019-04-11 12:42:47 +10:00
Robin Ward
db63a8e468 SECURITY: Update Handlebars to 4.1
This is to address: https://www.npmjs.com/advisories/755

It is a low priority fix, as Discourse does not allow end users to input
raw handlebars templates.
2019-04-10 16:15:12 -04:00
Neil Lalonde
63dbac786f Version bump to v2.2.4 2019-03-28 11:03:05 -04:00
Sam Saffron
e073593c86 SECURITY: properly validate return URL for SSO
Previously carefully crafted URLs could redirect off site
2019-03-25 09:04:13 +11:00
Jeff Wong
8b761cded1 FIX: remove extra periods (#6998)
Periods are belong in the translation files not in our templates, if we have them in the templates sentences can not be localized properly.
2019-03-15 15:47:00 -07:00
Jeff Wong
cbfd9595c4 FEATURE: Add plugin html hook to insert html before any other scripts 2019-03-15 15:38:49 -07:00
Jeff Wong
c9fd2679e4 FIX: lightbox wrapper within open details should show. 2019-03-15 15:38:49 -07:00
Vinoth Kannan
c395755051 FIX: Add helper file for compatibility with latest stable plugin 2019-03-14 09:04:05 +05:30
Roman Rizzi
d8c3c82345 Version bumped to v2.2.3 2019-03-13 16:39:39 -03:00
Roman Rizzi
0f6d5ba4f9 SECURITY: Upgrading Rails version to 5.2.2.1 2019-03-13 16:30:49 -03:00
Neil Lalonde
760d51cab1 Version bump to v2.2.2 2019-03-01 12:27:02 -05:00
Sam
3ac5f526be SECURITY: bypass long GET requests
In some rare cases we would check URLs with very large payloads
this ensures we always bypass and do not read entire payloads
2019-02-27 21:52:40 +11:00
David Taylor
c10941bbde REFACTOR: Proxy letter avatars in rails instead of nginx
Co-authored-by: Sam Saffron <sam.saffron@gmail.com>
Co-authored-by: David Taylor <david@taylorhq.com>

This gives more control over the request. In particular we can easily
lookup DNS dynamically, instead of only upon NGINX startup.
Previously, NGINX was looking up IP for the letter avatar service and
caching the CDN IP address, this caused issues if CDN changed IP, in
which letter avatars would be broken till a container restarted.

NGINX config has been updated to add caching. This change will require
a container rebuild.

The proxy will now function in development environments, so the patch
for `letter_avatar_proxy` has been removed.
2019-02-18 08:51:58 +11:00
Kris
4325d0ffc3 UX: Reduce font size on about pages
(cherry picked from commit 3d11064a33)
2019-02-14 20:12:55 -05:00
Sam
904e5ac09c FIX: unable to create new categories
Previous attempt at 70adb940 missed the critical "everyone" group from
staff, leading to a case where staff was no longer able to create categories
2019-02-15 10:28:13 +11:00
Bianca Nenciu
8e1efe6899 DEV: Improve test. 2019-02-14 23:04:38 +02:00
Bianca Nenciu
426810fcaf FIX: Fix failing test. 2019-02-14 23:04:34 +02:00
Bianca Nenciu
37214bc3eb SECURITY: Do not leak private group names. (#7008) 2019-02-14 23:04:32 +02:00
Vinoth Kannan
2fb5271069 FIX: Bump onebox version to include imgur security fix
(cherry picked from commit 36ff971c9c)
2019-02-13 11:51:15 +05:30
Vinoth Kannan
e11ae2a5ab FIX: Bump onebox version to include imgur security fix
(cherry picked from commit fb911766ee)
2019-02-13 11:50:35 +05:30
Arpit Jalan
e1094724fb FIX: some posters were not getting added to topic_allowed_users when moving posts to a new PM
If a user posted twice in a topic then subsequent posters were not getting added as topic_allowed_users.
2019-02-11 18:25:06 +05:30
Neil Lalonde
e9d1597f81 Version bump to v2.2.1 2019-02-07 10:56:03 -05:00
Kris
3ad5f6ea4b UX: checkboxes were too close to other inputs 2019-02-07 10:09:19 -05:00
Bianca Nenciu
589187b732 FIX: Fix delete button for Tag Groups. (#6965) 2019-02-07 10:09:16 -05:00
Kris
dc43fb69d1 UX: Minor button icon color fixes 2019-02-07 10:09:13 -05:00
Bianca Nenciu
beb6e154ef FIX: in:title should work irrespective of the order. (#6968) 2019-02-07 10:09:08 -05:00
Dan Ungureanu
cc983e3b11 UX: Use translatedLabel for aria-label in buttons. 2019-02-07 10:09:05 -05:00
Maja Komel
7426c427a1 fix typo 2019-02-07 10:09:02 -05:00
David Taylor
9f49007b7b FIX: Rescue and display import errors when updating theme via git 2019-02-07 10:08:59 -05:00
Sam
bfceb29db8 DEV: update logster to stable release
This update logster to the stable 2.0.1 release instead of running a pre
release
2019-02-07 10:08:56 -05:00
Gerhard Schlager
d576a3fa57 FIX: S3 endpoint broke bucket creation in non-default region 2019-02-07 10:08:53 -05:00
Kris
12cf3320c2 UX: Turn off autocomplete on composer title 2019-02-07 10:08:50 -05:00
Régis Hanol
1e9a884244 UX: disable browser's autocomplete in search menu 2019-02-07 10:08:47 -05:00
David Taylor
f01ca1f22d FIX: Correctly process {{each}} in raw handlebars templates for themes 2019-02-07 10:08:43 -05:00
Jeff Wong
9564eac72a FIX: Register pan events for touch only
* touch events - only register touch, not pointer events
* immediately request redraw frame, do not wait for after render to fire.
2019-02-07 10:08:40 -05:00
Gerhard Schlager
8573ac0d18 FIX: Unpause Sidekiq before uploading backup to S3
No need to pause Sidekiq longer than really needed. Uploads to S3 can take a long time.
2019-02-07 10:08:37 -05:00
Kris
a36527ca77 Minor icon color fix 2019-02-07 10:08:34 -05:00
Sam
894b98685b FIX: old migration was loading up invalid model schema
Generally we should never be touching AR objects in migrations, this is
super risky as we may end up with invalid schema cache.

This code from 2013 did it unconditionally. This change amends it so:

1. We only load up schema if we have no choice
2. We flush the cache before and after

This makes this migration far less risky.
2019-02-07 10:08:29 -05:00
Kris
5ef75197da UX: Header icon color fix 2019-02-01 17:50:00 +00:00
David Taylor
78eb51f780 SECURITY: Escape HTML in dashboard report tables 2019-02-01 13:11:14 +00:00
David Taylor
94ccedb730 FIX: Login button icons should be white 2019-02-01 11:41:54 +00:00
Kris
34f120c011 Header icon focus color fix 2019-02-01 10:50:40 +00:00
Neil Lalonde
bbb4b6ccef Version bump to v2.2.0 2019-01-31 17:41:36 -05:00
Neil Lalonde
87f89e92a8 Merge diffs from master 2019-01-31 17:24:35 -05:00
Neil Lalonde
23e2a01572 Merge master 2019-01-31 17:18:47 -05:00
Neil Lalonde
a49c0b9bbd Version bump to v2.1.8 2019-01-21 14:59:14 -05:00
Joffrey JAFFEUX
6418caf700 SECURITY: fix possible XSS with badges (#6912) 2019-01-21 13:12:09 +01:00
Neil Lalonde
d72d51711e Version bump to v2.1.7 2019-01-14 17:01:44 -05:00
Sam
4810a841a0 PERF: reduce workload when optimizing images
Previously, we would initialize an ImageOptim object each time we resize.

This object init is mega expensive (170ms on a VERY fast machine):

```
[1] pry(main)> Benchmark.measure { FileHelper.image_optim   }
=> #<Benchmark::Tms:0x00007f55440c1de0
 @cstime=0.055742,
 @cutime=0.141031,
 @label="",
 @real=0.17165619300794788,
 @stime=0.0002750000000000252,
 @total=0.19890400000000008,
 @utime=0.0018560000000000798>

```

This happens cause during init it hunts for all the right binaries and sets
up internals.

We now memoize this object to avoid a huge amount of pointless work.
2019-01-09 12:50:11 +11:00
Neil Lalonde
a632f3e899 Version bump to v2.1.6 2019-01-02 15:12:36 -05:00
Guo Xiang Tan
1590387bd1 SECURITY: Users can pick non-avatar uploads.
https://meta.discourse.org/t/bug-report-idor-on-avatar-pick-function-discussions-udacity-com/103564
2018-12-18 13:57:54 +08:00
Sam
69bc8f526a SECURITY: only allow picking of avatars created by self (#6417)
* SECURITY: only allow picking of avatars created by self

Also adds origin tracking to all uploads including de-duplicated uploads
2018-12-18 13:57:49 +08:00
Neil Lalonde
f1385cf72d Version bump to v2.1.5 2018-12-14 12:20:44 -05:00
David Taylor
62ec0f92ea FIX: Only serialize group membership domains for administrators (#6771) 2018-12-14 15:49:05 +00:00
Sam
d535e1ce6d SECURITY: do not delete avatars uploads when deleting accounts
We rely on the clean up uploads job to do this safely
2018-12-13 16:32:35 +11:00
Sam
1b34a8b48a FIX: remove slow platform detection from server side
Historically due to https://meta.discourse.org/t/why-is-discourse-so-slow-on-android/8823
we decreased page sizes of both home page and topic page on android by half.

This was done on the server side and as a side effect and caused page sizes on android
to mismatch between Android and non Android.

Unfortunately about a year ago googlebot started pretending it is Android,
this cause Google to start indexing pages as what android would see. So
it saw double the amount of pages in the index as what exists on desktop.
This in turn caused double the amount of indexing work and a large amount
of broken links on long topics.

This fix removes all special behavior which is no longer needed due to
other performance work in Discourse including raw handlebars on home page
and virtual dom on topic pages.

I tested we do not need this on Blu Advance 5.0 it has 1.3 GHZ mediatec mt6580
This phone retails for around $50 USD.

If we decide long term that we want any hacks like this we will shift them
to the client side. It can just hold data in memory without rendering.
2018-12-13 16:14:37 +11:00
David Taylor
7828c1156c FIX: Do not serialize user fields unless they are specified for display (#6736) 2018-12-07 11:08:59 +00:00
Guo Xiang Tan
cffb3d7976 SECURITY: Require groups to be given when inviting to a restricted category. (#6715) 2018-12-07 15:54:53 +08:00
Neil Lalonde
e8b51feceb Version bump to v2.1.4 2018-11-29 11:16:23 -05:00
Sam
6b9b73236a SECURITY: enforce hostname to match discourse hostname
This ensures that the hostname rails uses for various helpers always matches
the Discourse hostname

# Conflicts:
#	config/application.rb
#	spec/requests/application_controller_spec.rb
2018-11-15 16:17:22 +11:00
Sam
05b2c5babf SECURITY: update rack from 2.0.5 to 2.0.6
This release contains security fixes to the underlying rack library
used by Discourse.

Impact is not too high as we do not use request.scheme in our templates
2018-11-07 10:06:24 +11:00
David Taylor
e16c1206e5 Version bump to v2.1.3 2018-11-05 11:08:19 +00:00
David Taylor
43ad60d52c SECURITY: Add CSRF protections to OpenID callback 2018-11-05 11:07:35 +00:00
Joffrey JAFFEUX
d37e8e17ef UX: bumps the user-api-key version to 3 (#6526)
* UX: bumps the user-api-key version to 3

* fix spec
2018-11-01 21:29:29 +01:00
Joffrey JAFFEUX
5a114df088 FEATURE: adds latest to user-api-key session scope 2018-11-01 21:29:19 +01:00
Joffrey JAFFEUX
b8aec7777c FEATURE: adds list#(unread|new) to user api key routes (#6494) 2018-11-01 21:29:13 +01:00
Joffrey JAFFEUX
38ad1b96cb FEATURE: adds header text/background color to site (#6462) 2018-11-01 21:29:04 +01:00
Kyle Zhao
5e054e00da SECURITY: update loofah for CVE-2018-16468 2018-10-30 11:37:35 -04:00
Neil Lalonde
caae57a496 Version bump to v2.1.2 2018-10-12 10:46:12 -04:00
Guo Xiang Tan
40559b3881 Fix UploadRecovery from S3 fails with bucket name containing sub-folder. 2018-10-01 20:22:15 +08:00
Guo Xiang Tan
05fe5c9188 Fix onceoff job in cfa7173da3 not running. 2018-10-01 18:37:05 +08:00
Guo Xiang Tan
cf60ae32ea FIX: Onceoff job to fix missing user profile backgrounds. 2018-10-01 18:31:09 +08:00
Sam
b6e7992a3d FIX: correct readonly timeout
So it only applies in readonly mode
2018-09-20 15:19:46 +10:00
Sam
abc39c492a FIX: in redis readonly raise an exception from DistributedMutex
If we detect redis is in readonly we can not correctly get a mutex
raise an exception to notify caller

When getting optimized images avoid the distributed mutex unless
for some reason it is the first call and we need to generate a thumb

In redis readonly no thumbnails will be generated
2018-09-19 15:49:18 +10:00
Sam
d7d5db257b FIX: required rbtrace upgrade
trollop gem was renamed to optimist
2018-09-19 15:29:53 +10:00
Sam
7b70a208ba SECURITY: correct XSS on long topic titles 2018-09-18 08:56:10 +10:00
Sam
c662e0918f SECURITY: remove admin memory diagnostics routes 2018-09-18 08:36:24 +10:00
Guo Xiang Tan
852026dfae Backward compatibility for dropping functions in ColumnDropper.
https://meta.discourse.org/t/launcher-rebuild-error-pg-error-schema-discourse-functions-does-not-exist/96209
2018-09-17 14:52:09 +08:00
Neil Lalonde
b5401af2dc Version bump to v2.1.1 2018-09-14 11:00:12 -04:00
Guo Xiang Tan
8ddcb6564e FIX: Onceoff job to recover missing post uploads.
This fixes the regression due to 1f636c445b
2018-09-14 10:52:33 +08:00
Guo Xiang Tan
9d81a6cc72 DEV: Avoid using send and make the method public instead. 2018-09-14 10:52:16 +08:00
Guo Xiang Tan
ea522589cf Accept custom AR relation for UploadRecovery. 2018-09-14 10:51:55 +08:00
Guo Xiang Tan
1d6597c646 FIX: Do not try to recover invalid Upload#short_url in UploadRecovery. 2018-09-14 10:51:36 +08:00
Guo Xiang Tan
692f2aa395 Fix the build. 2018-09-14 10:51:26 +08:00
Guo Xiang Tan
2176605fc4 Add basic test case for UploadRecovery. 2018-09-14 10:51:20 +08:00
Guo Xiang Tan
50f7e2be64 Rescue errors when running dry run for UploadRecovery. 2018-09-14 10:51:11 +08:00
Guo Xiang Tan
d257b4a386 Fix s3 recovery from tombstone in UploadRecovery. 2018-09-14 10:51:04 +08:00
Guo Xiang Tan
c3c42fd056 Add dry run option to UploadRecovery. 2018-09-14 10:50:53 +08:00
Guo Xiang Tan
f08e7bdbff Fix incorrect variable. 2018-09-14 10:50:46 +08:00
Guo Xiang Tan
797a259702 New rake task uploads:recover. 2018-09-14 10:50:32 +08:00
Guo Xiang Tan
0811379ab3 DEV: Print the error class in uploads:list_posts_with_broken_images. 2018-09-14 10:50:26 +08:00
Guo Xiang Tan
dffd4fa9e6 Add extra protection in Upload#get_from_url.
In case the extension goes missing from the URL.
2018-09-14 10:49:34 +08:00
Régis Hanol
39a2d92417 FIX: don't index urls to local files 2018-09-14 12:31:35 +10:00
Arpit Jalan
74eec1849d FIX: ignore and log bad json values for custom fields 2018-09-13 17:42:48 +05:30
Guo Xiang Tan
f31758cc70 FIX: Uploads not being linked correctly to posts.
Regression due to 1f636c445b.
2018-09-11 23:54:07 -07:00
Neil Lalonde
8922a91c1c Version bump to v2.1.0 2018-09-10 19:39:59 -04:00
Neil Lalonde
ea7ee8e9f7 Merge master 2018-09-10 19:39:09 -04:00
Sam
a5ae7ee8e2 SECURITY: correct edge case when SSO provides unvalidated emails 2018-09-11 08:25:19 +10:00
Neil Lalonde
65cffedc33 Version bump to v2.0.5 2018-08-30 10:49:38 -04:00
David Taylor
825dee5598 SECURITY: Prevent users from modifying custom fields 2018-08-30 13:00:51 +01:00
Vinoth Kannan
3eff6a0e9b DEV: Export Tag class to modify methods in plugin 2018-08-30 16:53:02 +08:00
Guo Xiang Tan
c4de36624f Skip imagemagick tests on Travis. 2018-08-30 16:07:00 +08:00
Guo Xiang Tan
90802053a0 Fix linting on Travis for stable. 2018-08-30 16:04:56 +08:00
Guo Xiang Tan
032f860c86 Fix brittle spec. 2018-08-28 14:29:38 +08:00
Robin Ward
52ca0893e1 FIX: Broken specs 2018-08-28 14:29:38 +08:00
Neil Lalonde
911044f8a0 Version bump to v2.0.4 2018-08-21 11:53:29 -04:00
Guo Xiang Tan
5778c33ee7 FIX: Compatibility with ImageMagick 7.
http://www.imagemagick.org/Usage/misc/

"The "-interpolate" setting of 'Catrom' (generally imprecisely known as 'BiCubic' interpolation)"
2018-08-16 09:49:52 +08:00
Neil Lalonde
37a01975e9 SECURITY: prevent use of X-Forwarded-Host to perform XSS 2018-08-13 17:10:06 -04:00
Neil Lalonde
49681b762a Version bump to v2.0.3 2018-07-26 14:14:22 -04:00
David Taylor
6f5b8f61df FIX: Remove return statement from inside block 2018-07-26 16:00:45 +01:00
Régis Hanol
aeaf6b5a7c SECURITY: force IM decoder based on file extension - part 3 2018-07-25 23:55:41 +02:00
Régis Hanol
01714e40f4 SECURITY: force IM decoder based on file extension - part 2 2018-07-25 23:08:38 +02:00
Régis Hanol
b04b7c366c SECURITY: force IM decoder based on file extension 2018-07-25 22:01:08 +02:00
David Taylor
6520697b5c FIX: Remove plugin.enabled? checks at initialization time (#6166)
Checking `plugin.enabled?` while initializing plugins causes issues in two ways:
- An application restart is required for changes to take effect. A load-balanced multi-server environment could behave very weirdly if containers restart at different times.
- In a multisite environment, it takes the `enabled?` setting from the default site. Changes on that site affect all other sites in the cluster.

Instead, `plugin.enabled?` should be checked at runtime, in the context of a request. This commit removes `plugin.enabled?` from many `instance.rb` methods.

I have added a working `plugin.enabled?` implementation for methods that actually affect security/functionality:
- `post_custom_fields_whitelist`
- `whitelist_staff_user_custom_field`
- `add_permitted_post_create_param`
2018-07-25 16:51:45 +01:00
Robin Ward
878aee965b SECURITY: Consider 0.0.0.0 a private IP 2018-07-24 11:17:13 -04:00
Sam
cf9b4a789b FIX: update mini_racer in stable
This is required due to a bundler/build bug that means it is picking the wrong
version of libv8 when compiling mini_racer
2018-07-24 12:25:45 +10:00
Vinoth Kannan
b7ebb0268f FIX: returns provider_not_enabled error even if enabled 2018-07-16 11:08:48 +01:00
Sam
297b899c68 SECURITY: extra CORS headers should be set on correct host 2018-07-11 09:29:45 +10:00
David Taylor
6f25421a06 SECURITY: Do not allow authentication with disabled plugin-supplied a… (#6071)
Do not allow authentication with disabled plugin-supplied auth providers
2018-07-09 14:26:44 +10:00
Sam
849b4b5685 SECURITY: category badges should HTML escape names 2018-06-28 18:16:12 +10:00
Joffrey JAFFEUX
aafd883466 SECURITY: prevents XSS when showing tooltip 2018-06-27 14:53:31 +02:00
Dax74
612bc4f95b
Link updated
See https://meta.discourse.org/t/wrong-link-on-manual-admin-creation/90849
2018-06-27 11:41:03 +02:00
Neil Lalonde
34ad6749db FIX: missing translations for mobile flag modal 2018-06-25 20:21:47 -04:00
Neil Lalonde
365c99cf3f Version bump to v2.0.2 2018-06-21 10:39:00 -04:00
Sam
f2cb89b0d2 SECURITY: update sprockets for CVE-2018-3760 2018-06-20 09:50:28 +10:00
Guo Xiang Tan
a90364ac6c Monkey patch in 7830a950ef 2018-06-19 10:36:20 +08:00
Neil Lalonde
8c3380791b Version bump to v2.0.1 2018-06-12 12:13:47 -04:00
Joffrey JAFFEUX
5e4a1e812a UX: reworks dashboard problems section to be in line with new style 2018-06-12 11:48:53 -04:00
Arpit Jalan
57f5f7d755 FIX: do not show SSO external_email to moderators 2018-06-12 11:48:10 -04:00
Guo Xiang Tan
ff7cbf6935 FIX: Ensure we have proper timeout for MiniRacer. 2018-06-12 11:48:08 -04:00
Joe
7c9aa82625 FIX: adjust 2FA input width in mobile login form 2018-06-12 11:48:08 -04:00
Joe
1612c28718 FIX: adjust max-width of social login buttons for non-English locals 2018-06-12 11:48:07 -04:00
Neil Lalonde
a8d2d24a49 fix indent 2018-06-12 11:48:07 -04:00
Neil Lalonde
a279e43025 FIX: broken mailto href's in emails 2018-06-12 11:48:07 -04:00
Joffrey JAFFEUX
2b3faa8d0b FIX: do not use number helper for charts Y value 2018-06-12 11:48:06 -04:00
Joffrey JAFFEUX
940c0f569f FIX: incorrect backup and update times on dashboard 2018-06-12 11:48:06 -04:00
Joffrey JAFFEUX
e66d5425e4 FIX: slightly safer rounding 2018-06-12 11:48:06 -04:00
Joffrey JAFFEUX
2f84d43bb2 FIX: makes format number round the value before using parseInt 2018-06-12 11:48:05 -04:00
Joe
134300001c FIX: user-fields layout in desktop create account form 2018-06-12 11:48:05 -04:00
Joffrey JAFFEUX
7c57cd6897 FIX: removes buggy/unnecessary local-dates margin 2018-06-12 11:48:05 -04:00
Joe
cb9753267a FIX: user-fields layout in mobile create account form 2018-06-12 11:48:04 -04:00
Vinoth Kannan
17e7d3b526 FIX: avatar_url includes upload_path twice when local storage used 2018-06-12 11:48:04 -04:00
Guo Xiang Tan
b7865bac27 FIX: Permalink route matcher should always be last. 2018-06-12 11:48:04 -04:00
Guo Xiang Tan
a74d62d618 FIX: Disconnects all connections in the pool before forking.
* We were leaking connections as a result. Connections opened
  before the fork were never closed.
2018-06-12 11:48:03 -04:00
Régis Hanol
db3f31a841 FIX: unable to add new poll to post with a public poll 2018-06-12 11:48:03 -04:00
Joffrey JAFFEUX
9334d36a23 FIX: sharing popup not showing on macos/chrome
Despite `navigator.share` being defined the call was failing with this error:

```
sharing DOMException: Internal error: could not connect to Web Share interface.
```
2018-06-12 11:48:03 -04:00
Robin Ward
e37af71f2e FIX: Protection against dangling category group records 2018-06-12 11:48:02 -04:00
Robin Ward
abbb0ece4f FIX: Keyboard shortcuts didn't work on subfolders 2018-06-12 11:48:02 -04:00
Joe
08aca35b37 FIX: alignment for instructions on change email and 2FA fields 2018-06-12 11:48:02 -04:00
Blake Erickson
afbbdfc05f FIX: Allow a user to remove their title
Somewhere there was a regression and a user couldn't remove their own
title. If they selected '(none)' in the UI it would say it was saved,
but it would not actually be updated in the db.
2018-06-12 11:48:01 -04:00
Neil Lalonde
e90f80e788 Update translations 2018-06-08 10:45:46 -04:00
Neil Lalonde
894d287a7f Version bump to v2.0.0 2018-05-31 18:24:41 -04:00
Kris
0aa8d75be1 safety so pre blocks can't break modal width 2018-05-31 18:23:32 -04:00
Kris
12ebcc325b envelope missing on invite page, long pre lines making modals wide 2018-05-31 18:19:59 -04:00
Neil Lalonde
b675f5fa6b Merge master 2018-05-31 18:19:36 -04:00
Régis Hanol
82148a168f FIX: automatically fix image orientation 2018-05-17 14:55:58 +02:00
Neil Lalonde
fc0e50b34c Version bump to v1.9.7 2018-05-03 16:55:56 -04:00
Sam
3be4982186 clean up drag on iOS handling, we need it bound earlier 2018-04-30 15:58:03 +02:00
Sam
3fee06ae59 improve prev hack 2018-04-30 15:57:58 +02:00
Sam
2e0189afe9 FIX: dragging of timeline was flaky on iOS 2018-04-30 15:57:52 +02:00
Neil Lalonde
3b220d6102 Version bump to v1.9.6 2018-04-24 10:38:53 -04:00
Arpit Jalan
8d1e8fa712 SECURITY: do not show private topic title on /unsubscribed page 2018-04-16 20:05:31 +05:30
Régis Hanol
940b3a7c74 SECURITY: prevent XSS when showing diffs 2018-04-16 15:47:48 +02:00
Arpit Jalan
3edd6622df SECURITY: santize tags when creating new topic via URL 2018-04-16 01:07:47 +05:30
Arpit Jalan
27972c1202 SECURITY: escape HTML entities from topic title 2018-04-16 01:05:56 +05:30
Arpit Jalan
411696b85e SECURITY: do not disclose topic titles on /unsubscribed page to unauthorized users 2018-04-16 01:05:56 +05:30
Neil Lalonde
0bf1c476d7 Version bump to v1.9.5 2018-04-13 10:06:17 -04:00
Guo Xiang Tan
9c2be4dcac FIX: Restorer wasn't rolling back if restore fails.
* This only applies to backup file taken with
  pg_dump 10.3+ and pg_dump 9.5.12+.
2018-04-06 09:45:42 +08:00
Guo Xiang Tan
c39167f5da Fix incorrect function name. 2018-04-05 07:22:10 +08:00
Guo Xiang Tan
f038903423 Clean up unused function left in the database. 2018-04-05 07:22:03 +08:00
Michael Brown
6307790168 backup restorer: tidy pg_dump schema portability logic, add test 2018-04-04 16:51:25 +08:00
Michael Brown
6691a400da restorer: clarify logging 2018-04-04 16:51:20 +08:00
Guo Xiang Tan
e2f6d8b5ca FIX: Restorer was not extracting the patch version in dump file. 2018-04-04 16:51:00 +08:00
Guo Xiang Tan
833314f4b4 Improve grep pattern in restorer. 2018-04-04 16:50:50 +08:00
Guo Xiang Tan
837c0b9a77 Fix version check in restorer. 2018-04-04 16:50:40 +08:00
Guo Xiang Tan
3bccd8c8f3 FIX: Restore process for dump taken with pg_dump 10.3+.
* Since we can no longer restore into a different schema,
  we will move tables in the public schema into the backup schema
  first before restoring the dump file which goes into the public
  schema. The downside to this approach is that we will increase
  the downtime experienced during the restore process. Downtime
  would equal the duration of restoring the dump file.
2018-04-04 16:50:27 +08:00
Will Jordan
ab1ca72865 single quote password in restore command
> Followup to #3283. Quotes passwords passed to shell for backup restore.
2018-04-04 16:50:08 +08:00
Sam
c2ff0f1f3c Update libv8 from 5.9 to 6.3 2018-04-04 16:44:22 +08:00
Neil Lalonde
e24d25ce01 Version bump to v1.9.4 2018-03-07 15:16:48 -05:00
Neil Lalonde
e23b8e7905 SECURITY: sanitize topic title when staff is viewing a user's past flagged posts and deleted topics 2018-03-02 11:59:36 -05:00
Sam
e7f83358aa SECURITY: ensure users have permission when moving categories 2018-03-02 12:13:53 +11:00
Neil Lalonde
a745aa4a3e Version bump to v1.9.3 2018-02-15 17:46:48 -05:00
Sam
7174b100f9 SECURITY: correct local onebox category checks 2018-02-14 10:44:06 +11:00
Robin Ward
f655936b9d SECURITY: Prevent robots from indexing more routes
These routes could contain sensitive material and should never be
indexed for content.
2018-02-04 13:27:33 -05:00
Neil Lalonde
670450bcfc Version bump to v1.9.2 2018-01-23 16:50:09 -05:00
Gerhard Schlager
0ee2c2363b SECURITY: email domain whitelist could be bypassed 2018-01-17 21:49:43 +01:00
Neil Lalonde
b9bc27e539 Version bump to v1.9.1 2018-01-11 15:09:48 -05:00
Arpit Jalan
a13b8182e9 FIX: rescue login required / broken images 2018-01-11 14:30:34 -05:00
Arpit Jalan
f752c22104 FIX: handle invalid password reset token 2018-01-11 14:30:32 -05:00
Vinoth Kannan
8875993ae1 FIX: URI must be ascii only for URI.parse command 2018-01-11 14:30:29 -05:00
Arpit Jalan
243643bf76 FIX: render error message when backup download fails 2018-01-11 14:30:26 -05:00
Joffrey JAFFEUX
253711c233 FIX: correct shushing_face name 2018-01-11 14:30:22 -05:00
Arpit Jalan
bb4eab1267 FIX: do not create duplicate topics
https://meta.discourse.org/t/duplicate-http-https-topics-are-randomly-created/77190
2018-01-11 14:30:19 -05:00
Guo Xiang Tan
7c03b31006 Make rubocop happy. 2018-01-04 09:05:22 +08:00
Neil Lalonde
eaf083f9f0 Version bump to v1.9.0 2018-01-03 16:49:31 -05:00
Neil Lalonde
f83a39f8ba Merge master 2018-01-03 16:49:06 -05:00
Neil Lalonde
c45964bbfd Version bump to v1.8.11 2017-12-20 18:49:18 -05:00
Guo Xiang Tan
c6f5df4caa SECURITY: Don't pass email backup token to sidekiq as a parameter.
* This exposes the token in the Sidekiq dashboard which can be
  viewed by an admin and defeats the purpose of using a token
  in the download backup email ink.
2017-12-18 11:32:26 +08:00
Guo Xiang Tan
56b79ff2b9 Update .travis.yml. 2017-12-14 15:46:10 +08:00
Guo Xiang Tan
fcdd8491a1 Fix broken spec. 2017-12-14 15:43:50 +08:00
Guo Xiang Tan
6d475a15a8 SECURITY: Any group can be invited into a PM. 2017-12-14 15:18:27 +08:00
Sam
5748ad6f66 SECURITY: prevent staged accounts from changing email 2017-12-14 17:27:50 +11:00
Neil Lalonde
f18f608613 Version bump to v1.8.10 2017-10-30 11:18:24 -04:00
Neil Lalonde
504bcf4550 SECURITY: signup without verified email using Google auth 2017-10-16 15:23:32 -04:00
Neil Lalonde
3fd7f69972 Version bump to v1.8.9 2017-10-13 11:29:31 -04:00
Sam
a9bcc935b7 SECURITY: verify that inviter can invite new user to a topics 2017-10-11 09:49:45 +11:00
Neil Lalonde
834eef7b67 Version bump to v1.8.8 2017-09-28 15:19:43 -04:00
Guo Xiang Tan
5137ae8704 SECURITY: Update Nokogiri. 2017-09-25 21:19:35 +08:00
Neil Lalonde
8b6e4d1867 Version bump to v1.8.7 2017-09-14 10:37:26 -04:00
David Taylor
7cd4880e24 SECURITY: Only publish PM reply messagebus notifications to allowed users 2017-09-08 17:33:10 -04:00
Arpit Jalan
d4d548a874 Version bump to v1.8.6 2017-09-01 00:34:04 +05:30
Arpit Jalan
70d4c39bcd SECURITY: do not include links from whispers in topic summary map
https://meta.discourse.org/t/staff-whispers-links-in-whispers-showing-up-publicly-in-topics-summary/69134?u=techapj
2017-09-01 00:25:49 +05:30
Rafael dos Santos Silva
75364c6286 FIX: Make .eslintrc file compatible with eslint 4 take 2 2017-08-29 14:44:46 +08:00
Rafael dos Santos Silva
3413140346 FIX: Make .eslintrc file compatible with eslint 4 2017-08-29 14:44:02 +08:00
Guo Xiang Tan
5f0351348b FIX: Group name was being reverted to non-localized version.
https://meta.discourse.org/t/localized-staff-group-names-changed/65360/16
2017-08-29 14:42:07 +08:00
Neil Lalonde
3982a8ef30 Version bump to v1.8.5 2017-08-16 12:43:22 -04:00
David Taylor
77977dd32c SECURITY: Do not show latest/top topics on 404 for login_required sites 2017-08-13 23:47:41 +05:30
Neil Lalonde
ae8bd6c825 Version bump to v1.8.4 2017-08-01 14:23:50 -04:00
Guo Xiang Tan
62afa41f83 FIX: Exclude www in topic map links.
https://meta.discourse.org/t/topic-popular-links-panel-domain-extraction-doesnt-handle-country-tlds/60156/38?u=tgxworld
2017-07-26 09:58:58 +09:00
Guo Xiang Tan
1797994a63 Revert "UX: Don't try to figure out root domain."
This reverts commit 7690cc6ca5.
2017-07-26 09:58:48 +09:00
Robin Ward
70abd2b033 FIX: Allow discourse app to link directly to wizard 2017-07-10 14:35:51 -04:00
Neil Lalonde
53f3c54e4d Version bump to v1.8.3 2017-07-10 11:43:53 -04:00
Neil Lalonde
2fdbde0253 FIX: invited user should not be able to redeem invite as admin 2017-07-10 11:30:21 -04:00
Robin Ward
7ad2703397 SECURITY: Remove disposable invite feature 2017-07-07 20:52:21 -04:00
Neil Lalonde
b0be304591 Version bump to v1.8.2 2017-07-05 12:20:23 -04:00
Arpit Jalan
6eef7417ab FIX: include canonical meta tag on category pages 2017-07-03 14:45:16 +05:30
Robin Ward
3479298a71 FIX: Topic Entrance wasn't showing up on some suggested topics 2017-06-29 12:54:45 -04:00
Régis Hanol
04bc75b521 FIX: image orientation wasn't properly working 2017-06-23 10:19:38 +02:00
Guo Xiang Tan
787e4e6894 Pin eslint to version 3.x on travis. 2017-06-15 11:44:49 +08:00
Guo Xiang Tan
33291fdec0 Switch to yarn for our travis build. 2017-06-15 11:44:28 +08:00
Guo Xiang Tan
0fc10161a5 FIX: Send request membership PM to last 5 active group owner. 2017-06-15 11:39:16 +08:00
Guo Xiang Tan
84d46bceb9 FIX: Create group membership request on behalf of user. 2017-06-14 21:10:51 +09:00
Guo Xiang Tan
69dc8188e3 UX: Don't send emails for discobot notifications. 2017-06-14 21:09:47 +09:00
Guo Xiang Tan
88dacd4f6b Avoid monkey patching which causes weird reloading error in dev. 2017-06-14 21:09:38 +09:00
Robin Ward
e3bfcbc7c9 FIX: Don't fail seed if avatar can't be downloaded 2017-06-13 10:55:20 -04:00
Robin Ward
5d04cb4b47 FIX: Always allow the host the forum is hosted on 2017-06-13 10:55:15 -04:00
Robin Ward
4324ea024c FIX: Don't use target=_blank for local oneboxes 2017-06-13 10:55:10 -04:00
Robin Ward
28b241295d FIX: Onebox wasn't using correct uri 2017-06-13 10:55:05 -04:00
Robin Ward
075d0ecacc FIX: Support for cookies in onebox redirects 2017-06-13 10:54:56 -04:00
Robin Ward
502bca2c0d FIX: If HEAD is not supported, try GET. Also set cookies 2017-06-13 10:54:27 -04:00
Neil Lalonde
a4be79d297 padding below suggested topics on mobile 2017-06-12 16:13:40 -04:00
Neil Lalonde
91a75d98c8 Version bump to v1.8.1 2017-06-12 12:47:19 -04:00
Guo Xiang Tan
7b902c18a5 FIX: Bot mentioned check should be case insensitive. 2017-06-08 19:01:59 +09:00
Guo Xiang Tan
38cc6dec84 Move the constant as well. 2017-06-06 15:39:39 +09:00
Guo Xiang Tan
b19bc887e8 FIX: Ensure that we cancel any timeout jobs when terminating a track. 2017-06-05 16:28:25 +09:00
Guo Xiang Tan
c7108e077e FIX: Bot should only respond to regular posts. 2017-06-05 15:24:40 +09:00
Régis Hanol
5cd9236f17 FIX: PNG-to-JPEG conversion should only be done to images with at least 1 megapixels 2017-06-03 21:51:33 +02:00
Régis Hanol
a64ef19e39 FIX: automatic PNG-to-JPEG conversion should use a default white background 2017-06-03 21:51:25 +02:00
Guo Xiang Tan
d1b06624ff Revert "Skip validations when Discobot creates new posts."
This reverts commit ca7e906774.

Post validations are already skipped for admin users. Skipping
validations cause polls to not work.
2017-06-03 07:20:32 +09:00
Robin Ward
b906dc4f47 FIX: Don't run in testing mode 2017-06-02 13:08:50 -04:00
Neil Lalonde
81a9137be5 fix narrative bot for subfolder in translation files 2017-06-02 10:50:31 -04:00
Neil Lalonde
3582aa68bf FIX: narrative bot on subfolder installs 2017-06-02 10:50:21 -04:00
Robin Ward
d46f98a8d5 SECURITY: Vunerability in mail gem
(see https://github.com/mikel/mail/pull/1097)
2017-06-01 14:52:38 -04:00
Guo Xiang Tan
55f73fb31f Revert "Load posts in batches while indexing problem posts."
This reverts commit ce57ff9fcf.

Limit is ignored with `find_each`.
2017-06-01 11:31:23 +09:00
Neil Lalonde
d6ec9b3582 Version bump to v1.8.0 2017-05-31 16:18:32 -04:00
Neil Lalonde
44a0ff7688 Merge master 2017-05-31 16:16:17 -04:00
Neil Lalonde
7a434d51b0 Version bump to v1.7.10 2017-05-22 13:48:38 -04:00
Robin Ward
56f5b21a90 SECURITY: Validate the entity when downloading a CSV 2017-05-19 16:01:27 -04:00
Neil Lalonde
7f9c2f75b4 Version bump to v1.7.9 2017-05-15 11:45:43 -04:00
Guo Xiang Tan
d764f76dff Disable failing JS tests first. 2017-05-05 10:01:15 +08:00
Robin Ward
067a54f0df FIX: Regression when clicking on post date 2017-05-04 13:51:24 -04:00
Guo Xiang Tan
989d52a854 FIX: Show share popup only for valid buttons. 2017-05-04 11:20:06 -04:00
Guo Xiang Tan
790acfd99f SECURITY: XSS issue in share popup if invalid link is passed in. 2017-05-04 11:07:49 -04:00
Neil Lalonde
d143cde643 Version bump to v1.7.8 2017-04-10 14:25:07 -04:00
Sam Saffron
f09ca88c47 SECURITY: prefer render plain/html to render text where possible 2017-04-10 08:09:55 -04:00
Sam Saffron
e5c6d0ea65 SECURITY: do not send push notifications to suspended users 2017-04-05 08:29:43 -04:00
Neil Lalonde
33ac94534b Version bump to v1.7.7 2017-03-28 11:32:01 -04:00
Robin Ward
6ede1887b9 FIX: Update omniauth facebook to fix facebook logins 2017-03-27 17:25:23 -04:00
Guo Xiang Tan
e6f06f020d Version bump to v1.7.6 2017-03-23 10:43:43 +08:00
Guo Xiang Tan
db41af1c3c SECURITY: CSRF vulnerabilities in Admin::BackupsController. 2017-03-23 10:42:21 +08:00
Neil Lalonde
15b0a9a16f Version bump to v1.7.5 2017-03-20 11:59:53 -04:00
Guo Xiang Tan
2daed01070 SECURITY: Disallow symlinks when restoring uploads. 2017-03-17 14:29:37 +08:00
Robin Ward
c14d98354b SECURITY: Don't use backticks for exporting your archive 2017-03-16 16:27:52 -04:00
Sam
0f6a2b912a SECURITY: always allow staff to resend activation mails 2017-03-13 10:33:21 -04:00
Guo Xiang Tan
1c44c87945 FIX: Store user's id instead for sending activation email.
* Email and username are both allowed to be used for logging in.
  Therefore, it is easier to just store the user's id rather than
  to store the username and email in the session.
2017-03-13 20:57:21 +08:00
Guo Xiang Tan
8c5e13afd6 SECURITY: Only allow users to resend activation email with a valid session.
* Improve error when an active user tries to request for an activation email.
2017-03-13 20:57:17 +08:00
Guo Xiang Tan
395f43d92f FIX: Don't mark user as active if verified email is different. 2017-03-13 20:57:02 +08:00
Neil Lalonde
f6b43f987c Version bump to v1.7.4 2017-03-08 12:18:34 -05:00
Robin Ward
2c9a43e4fd Revert "SECURITY: Ensure oAuth authenticated email is the same as created user's email."
This reverts commit 1060239e2d.
2017-02-27 13:37:08 -05:00
Guo Xiang Tan
415bad645e FIX: Mobile topic timeline broken on Chrome 56.
* See https://developers.google.com/web/updates/2017/01/scrolling-intervention.
  From Chrome 56 onwards, `touchstart` event listeners are treated as passive
  by default which does not call `preventDefault` resulting in the page
  scrolling when topic timeline handle is being dragged.
2017-02-27 13:21:41 +08:00
Guo Xiang Tan
5cd680b0be SECURITY: Ensure oAuth authenticated email is the same as created user's email. 2017-02-24 15:40:31 +08:00
Guo Xiang Tan
465660bdfc Revert "SECURITY: Ensure that user has been authenticated."
This reverts commit d1091f7f57.
2017-02-24 15:39:56 +08:00
Guo Xiang Tan
d1091f7f57 SECURITY: Ensure that user has been authenticated. 2017-02-24 11:46:59 +08:00
Sam
7912966209 SECURITY: inactive/suspended accounts should be banned from api
Also fixes edge cases around users presenting multiple credentials
2017-02-17 11:09:08 -05:00
Neil Lalonde
a86807b39b Version bump to v1.7.3 2017-02-13 16:45:01 -05:00
Sam
47b9eb6dbb new: server plugin outlet for indexable robots.txt 2017-02-13 14:05:08 -05:00
Sam
1d3f04d4bb SECURITY: correctly validate input when admin searches for screened ips 2017-02-06 16:11:48 -05:00
Sam
5fc70471be UX: less restrictive selector to allow for plugin outlets
Currently plugin outlets in LIs will generate a wrapping SPAN,
this makes an allowence in core for nave extenstions (like solved does)
2017-02-02 12:18:22 -05:00
Neil Lalonde
839a5e6e42 Version bump to v1.7.2 2017-01-26 13:32:57 -05:00
Robin Ward
2f78facb48 SECURITY: Prevent large onebox downloads, better timeout support 2017-01-25 14:59:35 -05:00
Guo Xiang Tan
d4ca8ea617 Fix broken emojis. 2017-01-24 16:18:39 +08:00
Régis Hanol
f49c9f6c43 FIX: log backups download/destroy staff action
FIX: clean up junk left by the specs
RENAME: 'backup_operation' to 'backup_create' to match other backup log types
2017-01-16 19:58:04 +01:00
Robin Ward
8f34c2332d Version bump to v1.7.1 2017-01-13 11:08:58 -05:00
Régis Hanol
9f3c38832e FIX: don't onebox to IP addresses 2017-01-12 22:36:59 +01:00
Neil Lalonde
d20cbfb2b3 Version bump to v1.7.0 2017-01-06 16:08:01 -05:00
Neil Lalonde
be2fa971df Merge master 2017-01-06 15:56:48 -05:00
Robin Ward
ad9af94ac9 SECURITY: Moderators should not be able to access customizations 2017-01-06 14:43:30 -05:00
Guo Xiang Tan
b0fe5d383e Version bump to 1.6.10. 2016-12-21 12:07:13 +08:00
Guo Xiang Tan
33a05b9406 SECURITY: Users can only bookmark posts which they can see. 2016-12-21 12:06:56 +08:00
Sam
c10dfe0d1b SECURITY: prevent reuse of password reset 2016-12-19 18:04:55 +11:00
Sam
9db22bfd3d SECURITY: update onebox gem 2016-12-19 13:21:47 +11:00
Sam
402f06de27 SECURITY: protect upload params, only allow very strict filenames 2016-12-19 10:18:32 +11:00
Neil Lalonde
8a461e6283 Version bump to v1.6.9 2016-12-14 14:56:40 -05:00
Robin Ward
edeabc81a9 SECURITY: Update to latest onebox gem 2016-12-14 12:51:32 -05:00
Neil Lalonde
af0fbb693e Version bump to v1.6.8 2016-11-28 16:05:54 -05:00
Robin Ward
f71c9758a9 Backport get-owner API so plugins can use it safely 2016-11-21 11:16:49 -05:00
Rafael dos Santos Silva
64b0a4eada Version bump to v1.6.7 2016-11-14 19:27:06 -02:00
Sam
bdbd01ce40 fix oops 2016-11-14 19:24:46 -02:00
Sam
4c226bf12d FIX: properly reset all contexts after forking
Fixes hang on backup
2016-11-14 19:24:34 -02:00
Rafael dos Santos Silva
d5ba32ab2f Version bump to v1.6.6 2016-11-03 22:01:37 -02:00
Sam
90ef577037 FIX: mini_racer will no longer Dispose forked isolates 2016-11-03 20:05:59 -02:00
Sam
98d87a3ed2 update mini_racer to latest version 2016-11-03 20:05:53 -02:00
Neil Lalonde
1d76d255d5 Version bump to v1.6.5 2016-11-02 13:46:41 -04:00
Guo Xiang Tan
2bce183581 FIX: User enabled readonly mode was not working. 2016-10-25 11:50:51 +08:00
Guo Xiang Tan
2c86c202e5 FIX: Randomly failing specs try 2. 2016-09-23 15:05:03 +08:00
Guo Xiang Tan
46732957bc Version bump to v1.6.4 2016-09-23 14:48:07 +08:00
Guo Xiang Tan
5b3cbd3c9d FIX: Make sure constant reflects the right backup extenstion. 2016-09-23 14:46:59 +08:00
Guo Xiang Tan
e4c5cb84cd Version bump to v1.6.3 2016-09-19 08:54:54 +08:00
cpradio
ef440a4381 Escape the hyphen 2016-09-19 08:54:21 +08:00
cpradio
69691fa7a6 FIX: Backup validation wasn't escaping hyphens
Conflicts:
	spec/controllers/admin/backups_controller_spec.rb
2016-09-19 08:53:54 +08:00
Neil Lalonde
cbe623aaee Version bump to v1.6.2 2016-09-16 11:37:30 -04:00
Guo Xiang Tan
82fe884a7f SECURITY: Add filename validation for backup uploads. 2016-09-16 12:50:59 +08:00
Guo Xiang Tan
49ceac26d5 SECUIRTY: Escape input made to system calls. 2016-09-16 12:50:46 +08:00
Neil Lalonde
f7a335a64e Version bump to v1.6.1 2016-08-12 11:45:46 -04:00
Arpit Jalan
746ab933a0 Update Translations 2016-08-12 10:40:41 -04:00
Robin Ward
40d91ff504 FIX: Travis failure 2016-08-11 13:49:14 +08:00
Guo Xiang Tan
adb1e2cbc8 SECURITY: Escape HTML in filename. 2016-08-11 13:48:23 +08:00
Guo Xiang Tan
515024a0ac SECURITY: Escape image title in lightbox. 2016-08-11 11:17:37 +08:00
Régis Hanol
6d2a687ec7 FIX: wasn't able to update category's settings 2016-08-09 23:57:50 +02:00
Sam
0b5c3f5a03 SECURITY: do cookie auth rate limiting earlier 2016-08-09 10:04:49 +10:00
Guo Xiang Tan
1acef41e51 Revert "UX: Centering Badge notification styles on mobile."
This reverts commit fce902ab1e.
2016-08-08 09:36:07 +08:00
Neil Lalonde
4c14894958 Version bump to v1.6.0 2016-08-05 15:15:00 -04:00
Neil Lalonde
2499b56594 Merge master 2016-08-05 15:13:33 -04:00
Robin Ward
b17908fab1 SECURITY: XSS issue on Admin users list 2016-08-05 12:48:33 -04:00
Robin Ward
a139e469a7 SECURITY: Avoid mass assignment on user create 2016-08-05 12:43:50 -04:00
Robin Ward
a1e94cb1c1 FIX: Broken test 2016-08-05 12:41:29 -04:00
Robin Ward
9adfccfad1 FIX: Regression with escaping on badge page
In this branch (stable) we can't run the sanitizer because the bundle is not
loaded. The long badge description is not sanitized, but it
has to be created by an admin so it's extremely low risk.

In the beta / tests-passed branches the text is sanitized.
2016-07-28 16:11:41 -04:00
Robin Ward
5d062206db SECURITY: Make sure uploaded_urls have corresponding upload records 2016-07-28 15:41:03 -04:00
Robin Ward
f416634ea0 SECURITY: Cross-Site Scripting in Category and Group Settings 2016-07-28 15:30:53 -04:00
Robin Ward
80834df757 SECURITY: SQL Injection in Admin List Active Users 2016-07-28 15:29:16 -04:00
Robin Ward
90a3cc7f18 SECURITY: XSS in "Account Suspended" Messages and Badge Descriptions 2016-07-28 15:29:05 -04:00
Sam
f319923753 SECURITY: limit route access when using external avatars 2016-07-28 09:04:32 +10:00
Neil Lalonde
c8081af728 Version bump to v1.5.4 2016-07-26 11:47:38 -04:00
Guo Xiang Tan
cd5842d38b SECURITY: Possible SQL injection. 2016-07-19 13:03:00 +08:00
Neil Lalonde
ba3f7936a8 Version bump to v1.5.3 2016-06-21 11:44:32 -04:00
Sam
40a4aa4313 SECURITY: update logster 2016-06-20 12:15:54 +10:00
Sam
2b81c593f5 SECURITY: restrict constantize classes in search controller 2016-06-17 13:48:15 +10:00
Robin Ward
1e241dedad SECURITY: Unapproved, active users should not receive emails 2016-06-16 13:09:47 -04:00
Neil Lalonde
77d9467818 Version bump to v1.5.2 2016-05-19 12:23:46 -04:00
Sam
416e78796b SECURITY: update rack-mini-profiler 2016-05-18 18:34:02 +10:00
Régis Hanol
6dfd8ed47e SECURITY: 2 XSSs in post gutter and local oneboxes 2016-05-14 00:09:11 +02:00
Neil Lalonde
47e932159e Version bump to v1.5.1 2016-04-07 14:07:44 -04:00
Neil Lalonde
dc71f6b9d9 Update Translations 2016-04-07 13:51:31 -04:00
Neil Lalonde
01b6bc08ba Merge fixes from master 2016-04-07 13:51:05 -04:00
Neil Lalonde
aa91e4c1ac Version bump to v1.5.0 2016-03-31 17:51:08 -04:00
Robin Ward
b32d727d95 FIX: Bad auto merge 2016-03-31 17:42:16 -04:00
Neil Lalonde
01d0aeb5a9 merge master 2016-03-31 17:40:54 -04:00
Neil Lalonde
95f2ac6535 Version bump to v1.4.7 2016-03-17 12:18:18 -04:00
Arpit Jalan
331a9c8a2f SECURITY: Backport XSS fix 2016-03-08 21:08:05 +05:30
Régis Hanol
f9710d0d7c FIX: unescape emojis in digests 2016-03-08 21:05:50 +05:30
Neil Lalonde
7376e4000c Version bump to v1.4.6 2016-02-22 11:26:15 -05:00
Robin Ward
9f56d61305 Backported PluginAPI for compatibility with plugins 2016-02-17 12:19:07 -05:00
Régis Hanol
e953c1c5a6 fix eslint 2016-02-05 16:10:49 +01:00
Régis Hanol
28e4ea3178 we still need md5 2016-02-05 16:01:23 +01:00
Sam Saffron
45a166b315 SECURITY: hoist blocks using guids, not md5 hashes 2016-02-05 16:01:15 +01:00
Neil Lalonde
2e1aee861c Version bump to v1.4.5 2016-02-04 13:42:55 -05:00
Sam Saffron
51da6676f0 SECURITY: topic titles can show up in user page unescaped when streamed in 2016-02-01 21:02:23 +11:00
Régis Hanol
9e22fa91e8 SECURITY: fix XSS in lazyYT plugin 2016-01-30 12:40:54 +01:00
Neil Lalonde
304fc70079 Version bump to v1.4.4 2016-01-25 13:39:32 -05:00
Robin Ward
b792629208 FIX: Precompiler should apply get magic too 2016-01-15 15:26:19 -05:00
Robin Ward
2ad461f218 SECURITY: Upgrade Ember to fix CVE-2015-7565. Also upgrade Handlebars 2016-01-15 15:23:58 -05:00
Robin Ward
a0ee652f2e Revert "SECURITY: Upgrade Ember to fix CVE-2015-7565"
This reverts commit 211521df4f.
2016-01-15 11:39:56 -05:00
Robin Ward
8a61393d68 SECURITY: Upgrade Ember to fix CVE-2015-7565 2016-01-15 11:31:51 -05:00
Neil Lalonde
e7e6d370e0 Version bump to v1.4.3 2015-11-25 17:16:51 -05:00
Robin Ward
189595466c SECURITY: Backported XSS fixes from Handlebars 2015-11-24 16:30:52 -05:00
Robin Ward
e9f80464b4 SECURITY: XSS Protection on Queued Posts 2015-11-20 14:28:03 -05:00
Neil Lalonde
a324c71869 Version bump to v1.4.2 2015-10-19 17:33:28 -04:00
Robin Ward
c72f0160de SECURITY: Unread post notifications should respect whispers 2015-10-19 16:32:55 -04:00
Robin Ward
7f24b601c8 FIX: Broken spec 2015-10-14 16:13:42 -04:00
Robin Ward
b7bdaac081 SECURITY: Moderators should not see API keys 2015-10-14 15:46:46 -04:00
Sam
1fef49a094 SECURITY: XSS in search results term
Thanks to Jerbi Nessim
2015-10-07 10:53:48 +11:00
Neil Lalonde
04bd7d182f Version bump to v1.4.1 2015-10-02 11:06:58 -04:00
Sam
fe786dfc64 FIX: don't use Safari hack on Windows Phone 2015-09-28 17:20:54 +10:00
Robin Ward
41c5b262b2 FIX: max_topics_per_day was not working 2015-09-25 12:47:38 -04:00
Robin Ward
68a92e6656 FIX: Allow mods/admins to search whispers 2015-09-25 12:47:38 -04:00
Robin Ward
52ad4259d4 FIX: Replies to whispers *must* be whispers 2015-09-25 12:47:38 -04:00
Régis Hanol
e13906d5fb FIX: replaceMarkdown should be smart about current caret position 2015-09-25 12:47:38 -04:00
Sam
be8a20db67 FIX: disable cloaked view while running ios positioning hack 2015-09-25 12:47:38 -04:00
Sam
2f3bc60e59 FIX: whispers should not be revealed in reply to, or reply expansion
FEATURE: mark whisper as experimental
FIX: badges should never apply to whispers
2015-09-25 12:47:38 -04:00
Jeff Atwood
b1c81179f5 tweaks to readme 2015-09-25 12:47:38 -04:00
Jeff Atwood
241315ddd1 update readme images for 1.4 2015-09-25 12:47:37 -04:00
Jeff Atwood
3fa5180025 minor install guide tweaks 2015-09-25 12:47:37 -04:00
Jeff Atwood
64f6e41164 minor install guide tweaks 2015-09-25 12:47:37 -04:00
Sam
d7f2933743 FIX: when replying to a expanded reply, correctly attribute author 2015-09-25 12:47:37 -04:00
Jeff Atwood
80893a69ba FIX: 1.4 welcome PM images needed update 2015-09-25 12:47:37 -04:00
Robin Ward
7a155710dd FIX: Category Logo preview should not repeat 2015-09-25 12:47:37 -04:00
Régis Hanol
931812ce69 FIX: only disable the composer grip when the device is touch-only 2015-09-25 12:47:37 -04:00
Régis Hanol
33f689357a FIX: pikaday wasn't working when using the mouse with a touch-enabled monitor 2015-09-25 12:47:37 -04:00
Jeff Atwood
831223d815 emphasize reading the admin quick start guide 2015-09-25 12:47:37 -04:00
Jeff Atwood
5922e2cf26 simplify install guide a tiny bit 2015-09-25 12:47:37 -04:00
Jeff Atwood
49b4b503e3 update install guide for Discourse 1.4 2015-09-25 12:47:36 -04:00
Sam
b2e3703ae7 Revert "UX: always show logout link in user menu, use CSS to hide"
oops was on wrong branch

This reverts commit 2cbb49baec.
2015-09-25 12:16:17 +10:00
Sam
2cbb49baec UX: always show logout link in user menu, use CSS to hide
.menu-panel .logout-link {display: none}
2015-09-25 12:14:20 +10:00
Sam
60a8e203db Revert "FIX: properly filter badges when they're on a whisper"
This reverts commit 584a170534.
2015-09-25 10:22:08 +10:00
Régis Hanol
584a170534 FIX: properly filter badges when they're on a whisper 2015-09-25 00:39:39 +02:00
Régis Hanol
62b493281e FIX: notifications & messages were missing from user profile 2015-09-24 19:17:06 +02:00
Robin Ward
4236317f69 FIX: Double load sometimes on topic lists 2015-09-23 16:41:01 -04:00
Neil Lalonde
8be92d4de9 Version bump to v1.4.0 2015-09-22 15:08:51 -04:00
Neil Lalonde
65e159b073 Merge master 2015-09-22 15:00:32 -04:00
Neil Lalonde
a4c7f55a48 Version bump to v1.3.5 2015-09-09 11:38:13 -04:00
Sam
7bf12891f7 SECURITY: fix possible XSS expanding quotes 2015-09-08 15:27:48 +10:00
Neil Lalonde
30e2b579c1 Version bump to v1.3.4 2015-07-30 15:45:05 -04:00
Robin Ward
a716f9857b SECURITY: Make sure export CSV is generated via a POST 2015-07-24 12:38:58 -04:00
Neil Lalonde
e180e55c4e Version bump to v1.3.3 2015-07-17 11:21:48 -04:00
Sam
f8ba5346c4 SECURITY: Remove email validation check bypass
- Increase size of email column to varchar(513)
 - Give error message on signup when email is too large

Overall impact: Low, allows signups from blocked domains. Main risk is increased spam.
2015-07-14 09:46:00 +10:00
Neil Lalonde
bffaf5a117 Version bump to v1.3.2 2015-06-11 15:57:56 -04:00
Robin Ward
c2dde1ae88 PERF: Debounce mention lookup, enforce minimum username 2015-06-11 15:15:54 -04:00
Arpit Jalan
0083697dff FIX: fix category badge and link in email digest 2015-06-11 13:22:52 -04:00
Sam Saffron
32b17c628a SECURITY: Query @usernames in bulk
Otherwise you could add many requests at once while composing.
2015-06-11 13:12:01 -04:00
Sam Saffron
098b292c0f PERF: production assets not minified
source url post processor forcing all scripts into an eval,
  minifier can not minify such files
2015-06-11 10:06:11 -04:00
Sam Saffron
62e260c69c FEATURE: improve no-js topic list information
- Provide links to pages
- Provied link to last topic
2015-06-10 16:41:45 -04:00
Sam Saffron
51f9e3fc45 Attempt micro data using old vocubulary
Seeing weird results on Google
2015-06-10 16:41:39 -04:00
Arpit Jalan
0393aa63d4 FIX: when sending private message emails do not check email_direct setting 2015-06-10 16:41:33 -04:00
Robin Ward
ccaf525e8d FIX: Bad page title for categories view by google crawler 2015-06-10 16:41:27 -04:00
Arpit Jalan
ce0830b23f FIX: send 404 error when unauthorized user tries to download user archive 2015-06-10 16:41:23 -04:00
Régis Hanol
03fcf99039 FIX: missing emoji autocomplete 2015-06-10 16:40:39 -04:00
Régis Hanol
28d219dfed new 'uploads:migrate_to_new_pattern' task 2015-06-10 16:39:07 -04:00
Robin Ward
7302f6b60b Simple "cook" for email imports from mailing lists 2015-06-10 16:39:01 -04:00
cpradio
2c05e447c3 FEATURE: Use created_at to remove an ip if its last_match_at is null 2015-06-10 16:38:53 -04:00
Sam Saffron
e5d2b49119 correct specs 2015-06-10 16:38:47 -04:00
Sam Saffron
2c883833eb FEATURE: we need admin login always 2015-06-10 16:38:42 -04:00
Arpit Jalan
10c44763aa FIX: staff should be immune to max_invites_per_day setting 2015-06-10 16:38:37 -04:00
Neil Lalonde
f2353fa430 FEATURE: plugins can register a custom admin quick start topic that will be seeded into new sites 2015-06-10 16:38:22 -04:00
Régis Hanol
38090b0b94 we don't care about convert output/errors 2015-06-10 16:38:18 -04:00
Sam Saffron
7f35538bfc update memory profiler, oj and lru redux 2015-06-10 16:38:12 -04:00
Jeff Atwood
28c261238e lighter quote controls 2015-06-10 16:37:58 -04:00
Jeff Atwood
3a78783574 fix minor alignment issues with expanded posts 2015-06-10 16:37:52 -04:00
Sam Saffron
59ab3a7b2b SECURITY: expire all existing email tokens on password reset 2015-06-05 14:15:41 -04:00
Sam Saffron
3151192626 SECURITY: expire all existing sessions if user changes passwords 2015-06-05 13:18:59 -04:00
Robin Ward
ec88c08f24 Never enqueue posts from staff 2015-06-05 12:35:45 -04:00
Neil Lalonde
85b4e5fb0d Version bump to v1.3.1 (skip 1.3.0) 2015-06-03 17:03:29 -04:00
Neil Lalonde
4b0f33cc80 Version bump to v1.3.0 2015-06-03 16:52:09 -04:00
Neil Lalonde
8fec29ab32 Merge master 2015-06-03 16:51:28 -04:00
Neil Lalonde
1ca1c0d146 Revert "Version bump to v1.3.0" 2015-06-01 16:54:15 -04:00
Neil Lalonde
327781660f Version bump to v1.3.0 2015-06-01 15:28:01 -04:00
Neil Lalonde
3e317b40da Merge master 2015-06-01 15:27:35 -04:00
Neil Lalonde
4e187334b3 Version bump to v1.2.4 2015-05-11 18:52:22 -04:00
Sam
27b1e173fd Revert "S3 deprecation warning"
This reverts commit 1095e165d5.
2015-05-12 08:34:17 +10:00
Sam
e31e8ba0de Revert "add global notice for S3 deprecation warning"
This reverts commit d97d1d7438.
2015-05-12 08:34:04 +10:00
Neil Lalonde
dac7d92c75 Version bump to v1.2.3 2015-04-22 11:10:12 -04:00
Sam
34c3b2966c SECURITY: log off all existing sessions when resetting password 2015-04-15 09:05:18 +10:00
Neil Lalonde
9cb6ba0f8f Version bump to v1.2.2 2015-04-13 14:57:32 -04:00
Régis Hanol
d97d1d7438 add global notice for S3 deprecation warning 2015-03-30 11:29:48 +02:00
Neil Lalonde
ddaba0a148 add classes to global-notices so they can be found with selectors 2015-03-30 11:29:38 +02:00
Régis Hanol
1095e165d5 S3 deprecation warning 2015-03-25 18:35:48 +01:00
Neil Lalonde
590b73e25e Version bump to v1.2.1 2015-03-12 17:24:06 -04:00
Robin Ward
d57c5fc950 FIX: 6to5 was renamed to Babel
I can't believe they just pulled the old gem and broke people deploying
our site to production. I get it, your name changed, but don't break
other people's apps with no deprecations.
2015-03-05 13:37:30 -05:00
Sam
faad2c9013 Revert "FIX: when allow uncategorized was off we were still showing uncat for admins/mods"
This reverts commit e8ca1f9818.
2015-02-20 17:40:27 +11:00
Sam
e8ca1f9818 FIX: when allow uncategorized was off we were still showing uncat for admins/mods 2015-02-20 17:30:31 +11:00
Sam
b6bbf36c03 URGENT: commit snuck in twice when merging master 2015-02-20 11:15:12 +11:00
Neil Lalonde
f6e9293840 Version bump to v1.2.0 2015-02-19 16:19:48 -05:00
Neil Lalonde
16bea87fd3 Merge master 2015-02-19 16:17:51 -05:00
Robin Ward
980e97ec28 Merge pull request #3192 from riking/patch-xss
SECURITY: missed html escaping
2015-02-10 17:21:59 -05:00
Arpit Jalan
8205f65573 FIX: full user names were showing up in crawlers and rss feeds in spite enables_names setting being disabled 2015-01-22 12:38:00 -05:00
Robin Ward
f5e0cf63f6 SECURITY: The SSO return_path was an open redirect
This security fix needs SSO to be configured, and the user has to go
through the entire auth process before being redirected to the wrong host so
it is probably lower priority for most installs.
2015-01-22 12:33:07 -05:00
Robin Ward
f7f2e83cfb SECURITY: Don't whitelist codepen as it is a potential vector for abuse 2015-01-21 14:02:22 -05:00
Neil Lalonde
603108cd54 Version bump to v1.1.3 2014-12-12 14:37:30 -05:00
Régis Hanol
0138ecc99a SECURITY: prevent direct download of backups 2014-12-03 13:02:42 +01:00
Neil Lalonde
89f5ea02f6 Version bump to v1.1.2 2014-11-21 11:26:26 -05:00
Sam
abff1e88d4 FIX: PM title not editable 2014-11-21 11:09:35 +11:00
Régis Hanol
e0a4a7a9cd FEATURE: don't limit registration from an IP address if a staff member has that IP address 2014-11-21 00:34:31 +01:00
Jeff Atwood
4d1ac30233 fix pop up composer tips display for mobile 2014-11-21 00:34:24 +01:00
Neil Lalonde
6e0152ab94 Version bump to v1.1.1 2014-11-18 15:57:50 -05:00
Neil Lalonde
e210e08e95 Version bump to v1.1.0 2014-11-06 15:35:56 -05:00
Neil Lalonde
361aca1156 merge master 2014-11-06 15:26:38 -05:00
Neil Lalonde
35628c709b Version bump to v1.0.4 2014-10-30 16:55:05 -04:00
Robin Ward
013e3312ad SECURITY: Don't allow redirects with periods in case you don't control
other tlds on the same domain.
2014-10-30 11:32:26 -04:00
Régis Hanol
38e0c6645e FIX: prevent iframe in expended quote 2014-10-28 23:18:08 +01:00
Neil Lalonde
a412c3016e Version bump to v1.0.3 2014-10-03 11:00:33 -04:00
Robin Ward
59c1215e3b SECURITY: RegExp engine loopwith improperly formatted URLs. 2014-09-26 13:51:34 -04:00
Sam
48145e8e23 SECURITY: rate limit user/password login 2014-09-25 10:13:13 +10:00
Neil Lalonde
f02898f834 Version bump to v1.0.2 2014-09-23 13:17:32 -04:00
Neil Lalonde
6fe364e7ae SECURITY: rate limit change email requests 2014-09-18 10:49:43 -04:00
Robin Ward
570e3b3e79 SECURITY: Stripping links could unescape html fragments 2014-09-17 12:09:06 -04:00
Robin Ward
e4287d9de9 FIX: Resend activation email was busted 2014-09-16 10:24:02 -04:00
Sam Saffron
6646b23569 SECURITY: Escape strings in logs 2014-09-16 07:54:46 +10:00
Robin Ward
344991adb7 SECURITY: Malformed URL could crash V8 2014-09-12 13:21:04 -04:00
riking
3d3313d5ee SECURITY: Limit passwords to 200 characters
Prevents layer 8 attack.
2014-09-12 12:21:06 -04:00
Neil Lalonde
1f797d5d31 Version bump to v1.0.1 2014-09-05 12:29:45 -04:00
Sam
d7a2a65f1f SECURITY: GitHub authenticator returning unverified emails 2014-09-03 12:56:02 +10:00
Robin Ward
8ced44a766 SECURITY: User action route was returning too much data 2014-08-29 13:57:47 -04:00
Robin Ward
9ad246affe SECURITY: Only redirect to our host by path on the login action 2014-08-28 17:57:38 -04:00
268 changed files with 5516 additions and 2796 deletions

View File

@ -5,6 +5,8 @@ on:
push:
branches:
- main
- beta
- stable
concurrency:
group: tests-${{ format('{0}-{1}', github.head_ref || github.run_number, github.job) }}
@ -14,7 +16,7 @@ jobs:
build:
name: ${{ matrix.target }} ${{ matrix.build_type }}
runs-on: ubuntu-latest
container: discourse/discourse_test:slim${{ startsWith(matrix.build_type, 'frontend') && '-browsers' || '' }}
container: discourse/discourse_test:2.0.20220818-0047-slim${{ startsWith(matrix.build_type, 'frontend') && '-browsers' || '' }}
timeout-minutes: 60
env:
@ -36,8 +38,6 @@ jobs:
target: plugins
- build_type: frontend
target: core # Handled by core_frontend_tests job (below)
- build_type: frontend
target: plugins # Not yet passing in Ember CLI
include:
- build_type: frontend
target: core-plugins
@ -99,6 +99,10 @@ jobs:
if: matrix.target == 'plugins'
run: bin/rake plugin:install_all_official
- name: Pull compatible versions of plugins
if: matrix.target == 'plugins'
run: bin/rake plugin:pull_compatible_all
- name: Fetch app state cache
uses: actions/cache@v2
id: app-cache
@ -164,10 +168,10 @@ jobs:
run: QUNIT_EMBER_CLI=0 bin/rake plugin:qunit['*','1200000']
timeout-minutes: 30
- name: Plugin QUnit (Ember CLI)
if: matrix.build_type == 'frontend' && (matrix.target == 'plugins' || matrix.target == 'core-plugins')
run: QUNIT_EMBER_CLI=1 bin/rake plugin:qunit['*','1200000']
timeout-minutes: 30
# - name: Plugin QUnit (Ember CLI)
# if: matrix.build_type == 'frontend' && (matrix.target == 'plugins' || matrix.target == 'core-plugins')
# run: QUNIT_EMBER_CLI=1 bin/rake plugin:qunit['*','1200000']
# timeout-minutes: 30
- name: Check Annotations
if: matrix.build_type == 'annotations'
@ -186,61 +190,61 @@ jobs:
fi
timeout-minutes: 30
core_frontend_tests:
name: core frontend (${{ matrix.browser }})
runs-on: ubuntu-latest
container: discourse/discourse_test:slim-browsers
timeout-minutes: 30
# core_frontend_tests:
# name: core frontend (${{ matrix.browser }})
# runs-on: ubuntu-latest
# container: discourse/discourse_test:slim-browsers
# timeout-minutes: 30
strategy:
fail-fast: false
matrix:
browser: ["Chrome", "Firefox", "Headless Firefox"]
# strategy:
# fail-fast: false
# matrix:
# browser: ["Chrome", "Firefox", "Headless Firefox"]
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 1
# steps:
# - uses: actions/checkout@v2
# with:
# fetch-depth: 1
- name: Setup Git
run: |
git config --global user.email "ci@ci.invalid"
git config --global user.name "Discourse CI"
# - name: Setup Git
# run: |
# git config --global user.email "ci@ci.invalid"
# git config --global user.name "Discourse CI"
- name: Get yarn cache directory
id: yarn-cache-dir
run: echo "::set-output name=dir::$(yarn cache dir)"
# - name: Get yarn cache directory
# id: yarn-cache-dir
# run: echo "::set-output name=dir::$(yarn cache dir)"
- name: Yarn cache
uses: actions/cache@v2
id: yarn-cache
with:
path: ${{ steps.yarn-cache-dir.outputs.dir }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
# - name: Yarn cache
# uses: actions/cache@v2
# id: yarn-cache
# with:
# path: ${{ steps.yarn-cache-dir.outputs.dir }}
# key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
# restore-keys: |
# ${{ runner.os }}-yarn-
- name: Yarn install
working-directory: ./app/assets/javascripts/discourse
run: yarn install
# - name: Yarn install
# working-directory: ./app/assets/javascripts/discourse
# run: yarn install
- name: Ember Build
working-directory: ./app/assets/javascripts/discourse
run: |
sudo -E -u discourse mkdir /tmp/emberbuild
sudo -E -u discourse -H yarn ember build --environment=test -o /tmp/emberbuild
# - name: Ember Build
# working-directory: ./app/assets/javascripts/discourse
# run: |
# sudo -E -u discourse mkdir /tmp/emberbuild
# sudo -E -u discourse -H yarn ember build --environment=test -o /tmp/emberbuild
- name: Core QUnit 1
working-directory: ./app/assets/javascripts/discourse
run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=1 --launch "${{ matrix.browser }}"
timeout-minutes: 20
# - name: Core QUnit 1
# working-directory: ./app/assets/javascripts/discourse
# run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=1 --launch "${{ matrix.browser }}" --random
# timeout-minutes: 20
- name: Core QUnit 2
working-directory: ./app/assets/javascripts/discourse
run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=2 --launch "${{ matrix.browser }}"
timeout-minutes: 20
# - name: Core QUnit 2
# working-directory: ./app/assets/javascripts/discourse
# run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=2 --launch "${{ matrix.browser }}" --random
# timeout-minutes: 20
- name: Core QUnit 3
working-directory: ./app/assets/javascripts/discourse
run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=3 --launch "${{ matrix.browser }}"
timeout-minutes: 20
# - name: Core QUnit 3
# working-directory: ./app/assets/javascripts/discourse
# run: sudo -E -u discourse -H yarn ember exam --path /tmp/emberbuild --split=3 --partition=3 --launch "${{ matrix.browser }}" --random
# timeout-minutes: 20

View File

@ -18,7 +18,7 @@ else
# this allows us to include the bits of rails we use without pieces we do not.
#
# To issue a rails update bump the version number here
rails_version = '6.1.4.1'
rails_version = '6.1.7.1'
gem 'actionmailer', rails_version
gem 'actionpack', rails_version
gem 'actionview', rails_version
@ -263,3 +263,5 @@ gem 'colored2', require: false
gem 'maxminddb'
gem 'rails_failover', require: false
gem 'net-http'

View File

@ -8,22 +8,22 @@ GIT
GEM
remote: https://rubygems.org/
specs:
actionmailer (6.1.4.1)
actionpack (= 6.1.4.1)
actionview (= 6.1.4.1)
activejob (= 6.1.4.1)
activesupport (= 6.1.4.1)
actionmailer (6.1.7.1)
actionpack (= 6.1.7.1)
actionview (= 6.1.7.1)
activejob (= 6.1.7.1)
activesupport (= 6.1.7.1)
mail (~> 2.5, >= 2.5.4)
rails-dom-testing (~> 2.0)
actionpack (6.1.4.1)
actionview (= 6.1.4.1)
activesupport (= 6.1.4.1)
actionpack (6.1.7.1)
actionview (= 6.1.7.1)
activesupport (= 6.1.7.1)
rack (~> 2.0, >= 2.0.9)
rack-test (>= 0.6.3)
rails-dom-testing (~> 2.0)
rails-html-sanitizer (~> 1.0, >= 1.2.0)
actionview (6.1.4.1)
activesupport (= 6.1.4.1)
actionview (6.1.7.1)
activesupport (= 6.1.7.1)
builder (~> 3.1)
erubi (~> 1.4)
rails-dom-testing (~> 2.0)
@ -32,15 +32,15 @@ GEM
actionview (>= 6.0.a)
active_model_serializers (0.8.4)
activemodel (>= 3.0)
activejob (6.1.4.1)
activesupport (= 6.1.4.1)
activejob (6.1.7.1)
activesupport (= 6.1.7.1)
globalid (>= 0.3.6)
activemodel (6.1.4.1)
activesupport (= 6.1.4.1)
activerecord (6.1.4.1)
activemodel (= 6.1.4.1)
activesupport (= 6.1.4.1)
activesupport (6.1.4.1)
activemodel (6.1.7.1)
activesupport (= 6.1.7.1)
activerecord (6.1.7.1)
activemodel (= 6.1.7.1)
activesupport (= 6.1.7.1)
activesupport (6.1.7.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 1.6, < 2)
minitest (>= 5.1)
@ -129,7 +129,7 @@ GEM
sprockets (>= 3.3, < 4.1)
ember-source (2.18.2)
erubi (1.10.0)
excon (0.89.0)
excon (0.93.0)
execjs (2.8.1)
exifr (1.3.9)
fabrication (2.24.0)
@ -165,7 +165,7 @@ GEM
ffi (1.15.5)
fspath (3.1.2)
gc_tracer (1.5.1)
globalid (1.0.0)
globalid (1.0.1)
activesupport (>= 5.0)
guess_html_encoding (0.0.11)
hana (1.3.7)
@ -231,7 +231,7 @@ GEM
rack (>= 1.1.3)
method_source (1.0.0)
mini_mime (1.1.2)
mini_portile2 (2.6.1)
mini_portile2 (2.8.0)
mini_racer (0.6.1)
libv8-node (~> 16.10.0.0)
mini_scheduler (0.13.0)
@ -248,15 +248,19 @@ GEM
multi_xml (0.6.0)
multipart-post (2.1.1)
mustache (1.1.1)
net-http (0.2.2)
uri
nio4r (2.5.8)
nokogiri (1.12.5)
mini_portile2 (~> 2.6.1)
nokogiri (1.13.4)
mini_portile2 (~> 2.8.0)
racc (~> 1.4)
nokogiri (1.12.5-arm64-darwin)
nokogiri (1.13.4-aarch64-linux)
racc (~> 1.4)
nokogiri (1.12.5-x86_64-darwin)
nokogiri (1.13.4-arm64-darwin)
racc (~> 1.4)
nokogiri (1.12.5-x86_64-linux)
nokogiri (1.13.4-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.13.4-x86_64-linux)
racc (~> 1.4)
oauth (0.5.8)
oauth2 (1.4.7)
@ -318,12 +322,12 @@ GEM
rack (>= 1.2.0)
rack-protection (2.1.0)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
rack-test (2.0.2)
rack (>= 1.3)
rails-dom-testing (2.0.3)
activesupport (>= 4.2.0)
nokogiri (>= 1.6)
rails-html-sanitizer (1.4.2)
rails-html-sanitizer (1.4.3)
loofah (~> 2.3)
rails_failover (0.7.3)
activerecord (~> 6.0)
@ -332,11 +336,11 @@ GEM
rails_multisite (4.0.0)
activerecord (> 5.0, < 7)
railties (> 5.0, < 7)
railties (6.1.4.1)
actionpack (= 6.1.4.1)
activesupport (= 6.1.4.1)
railties (6.1.7.1)
actionpack (= 6.1.7.1)
activesupport (= 6.1.7.1)
method_source
rake (>= 0.13)
rake (>= 12.2)
thor (~> 1.0)
rainbow (3.1.1)
raindrops (0.20.0)
@ -455,7 +459,7 @@ GEM
test-prof (1.0.7)
thor (1.2.1)
tilt (2.0.10)
tzinfo (2.0.4)
tzinfo (2.0.5)
concurrent-ruby (~> 1.0)
uglifier (4.2.0)
execjs (>= 0.3.0, < 3)
@ -467,6 +471,7 @@ GEM
kgio (~> 2.6)
raindrops (~> 0.7)
uniform_notifier (1.14.2)
uri (0.11.0)
uri_template (0.7.0)
webmock (3.14.0)
addressable (>= 2.8.0)
@ -477,7 +482,7 @@ GEM
jwt (~> 2.0)
xorcist (1.1.2)
yaml-lint (0.0.10)
zeitwerk (2.5.3)
zeitwerk (2.6.6)
PLATFORMS
aarch64-linux
@ -489,14 +494,14 @@ PLATFORMS
x86_64-linux
DEPENDENCIES
actionmailer (= 6.1.4.1)
actionpack (= 6.1.4.1)
actionview (= 6.1.4.1)
actionmailer (= 6.1.7.1)
actionpack (= 6.1.7.1)
actionview (= 6.1.7.1)
actionview_precompiler
active_model_serializers (~> 0.8.3)
activemodel (= 6.1.4.1)
activerecord (= 6.1.4.1)
activesupport (= 6.1.4.1)
activemodel (= 6.1.7.1)
activerecord (= 6.1.7.1)
activesupport (= 6.1.7.1)
addressable
annotate
aws-sdk-s3
@ -557,6 +562,7 @@ DEPENDENCIES
mock_redis
multi_json
mustache
net-http
nokogiri
oj (= 3.13.2)
omniauth
@ -576,7 +582,7 @@ DEPENDENCIES
rack-protection
rails_failover
rails_multisite
railties (= 6.1.4.1)
railties (= 6.1.7.1)
rake
rb-fsevent
rbtrace
@ -618,4 +624,4 @@ DEPENDENCIES
yaml-lint
BUNDLED WITH
2.3.4
2.3.16

View File

@ -4,8 +4,6 @@ import I18n from "I18n";
import { alias } from "@ember/object/computed";
import bootbox from "bootbox";
import discourseComputed from "discourse-common/utils/decorators";
import { extractDomainFromUrl } from "discourse/lib/utilities";
import { isAbsoluteURL } from "discourse-common/lib/get-url";
import { isEmpty } from "@ember/utils";
import { popupAjaxError } from "discourse/lib/ajax-error";
@ -88,44 +86,20 @@ export default Controller.extend({
actions: {
save() {
this.set("saved", false);
const url = this.get("model.payload_url");
const domain = extractDomainFromUrl(url);
const model = this.model;
const isNew = model.get("isNew");
const saveWebHook = () => {
return model
.save()
.then(() => {
this.set("saved", true);
this.adminWebHooks.get("model").addObject(model);
return model
.save()
.then(() => {
this.set("saved", true);
this.adminWebHooks.get("model").addObject(model);
if (isNew) {
this.transitionToRoute("adminWebHooks.show", model.get("id"));
}
})
.catch(popupAjaxError);
};
if (
domain === "localhost" ||
domain.match(/192\.168\.\d+\.\d+/) ||
domain.match(/127\.\d+\.\d+\.\d+/) ||
isAbsoluteURL(url)
) {
return bootbox.confirm(
I18n.t("admin.web_hooks.warn_local_payload_url"),
I18n.t("no_value"),
I18n.t("yes_value"),
(result) => {
if (result) {
return saveWebHook();
}
if (isNew) {
this.transitionToRoute("adminWebHooks.show", model.get("id"));
}
);
}
return saveWebHook();
})
.catch(popupAjaxError);
},
destroy() {

View File

@ -25,12 +25,14 @@ export default Controller.extend(ModalFunctionality, {
importUrl: "/admin/themes/import",
recordType: "theme",
checkPrivate: match("uploadUrl", /^ssh\:\/\/.*\@.*\.git$|.*\@.*\:.*\.git$/),
privateKey: null,
localFile: null,
uploadUrl: null,
uploadName: null,
advancedVisible: false,
selectedType: alias("themesController.currentTab"),
component: equal("selectedType", COMPONENTS),
urlPlaceholder: "https://github.com/discourse/sample_theme",
init() {
this._super(...arguments);
@ -79,17 +81,24 @@ export default Controller.extend(ModalFunctionality, {
);
},
@discourseComputed("privateChecked")
urlPlaceholder(privateChecked) {
return privateChecked
? "git@github.com:discourse/sample_theme.git"
: "https://github.com/discourse/sample_theme";
@discourseComputed("name")
nameTooShort(name) {
return !name || name.length < MIN_NAME_LENGTH;
},
@observes("privateChecked")
@discourseComputed("component")
placeholder(component) {
if (component) {
return I18n.t("admin.customize.theme.component_name");
} else {
return I18n.t("admin.customize.theme.theme_name");
}
},
@observes("checkPrivate")
privateWasChecked() {
const checked = this.privateChecked;
if (checked && !this._keyLoading) {
const checked = this.checkPrivate;
if (checked && !this._keyLoading && !this.publicKey) {
this._keyLoading = true;
ajax(this.keyGenUrl, { type: "POST" })
.then((pair) => {
@ -105,40 +114,29 @@ export default Controller.extend(ModalFunctionality, {
}
},
@discourseComputed("name")
nameTooShort(name) {
return !name || name.length < MIN_NAME_LENGTH;
},
@discourseComputed("component")
placeholder(component) {
if (component) {
return I18n.t("admin.customize.theme.component_name");
} else {
return I18n.t("admin.customize.theme.theme_name");
@discourseComputed("selection", "themeCannotBeInstalled")
submitLabel(selection, themeCannotBeInstalled) {
if (themeCannotBeInstalled) {
return "admin.customize.theme.create_placeholder";
}
},
@discourseComputed("selection")
submitLabel(selection) {
return `admin.customize.theme.${
selection === "create" ? "create" : "install"
}`;
},
@discourseComputed("privateChecked", "checkPrivate", "publicKey")
showPublicKey(privateChecked, checkPrivate, publicKey) {
return privateChecked && checkPrivate && publicKey;
@discourseComputed("checkPrivate", "publicKey")
showPublicKey(checkPrivate, publicKey) {
return checkPrivate && publicKey;
},
onClose() {
this.setProperties({
duplicateRemoteThemeWarning: null,
privateChecked: false,
privateKey: null,
localFile: null,
uploadUrl: null,
publicKey: null,
privateKey: null,
branch: null,
selection: "popular",
});
@ -209,11 +207,9 @@ export default Controller.extend(ModalFunctionality, {
options.data = {
remote: this.uploadUrl,
branch: this.branch,
public_key: this.publicKey,
private_key: this.privateKey,
};
if (this.privateChecked) {
options.data.private_key = this.privateKey;
}
}
if (this.get("model.user_id")) {

View File

@ -16,6 +16,7 @@ EmailPreview.reopenClass({
sendDigest(username, lastSeenAt, email) {
return ajax("/admin/email/send-digest.json", {
type: "POST",
data: { last_seen_at: lastSeenAt || oneWeekAgo(), username, email },
});
},

View File

@ -1,7 +1,7 @@
<div class="field">{{i18n name}}</div>
<div class="value">
{{#if editing}}
{{text-field value=buffer autofocus="autofocus" autocomplete="discourse"}}
{{text-field value=buffer autofocus="autofocus" autocomplete="off"}}
{{else}}
<a href {{action "edit"}} class="inline-editable-field">
<span>{{value}}</span>

View File

@ -26,9 +26,10 @@
value=newValue
placeholderKey="admin.site_settings.simple_list.add_item"
class="add-value-input"
autocomplete="discourse"
autocomplete="off"
autocorrect="off"
autocapitalize="off"}}
autocapitalize="off"
}}
{{d-button
action=(action "addValue")

View File

@ -20,7 +20,8 @@
{{input
class="filter-input"
placeholder=(i18n "admin.customize.theme.filter_placeholder")
autocomplete="discourse"
autocomplete="off"
type="search"
value=(mut filterTerm)
}}
{{d-icon "search"}}

View File

@ -68,26 +68,16 @@
<div class="label">{{i18n "admin.customize.theme.remote_branch"}}</div>
{{input value=branch placeholder="master"}}
</div>
{{/if}}
<div class="check-private">
<label>
{{input type="checkbox" checked=privateChecked}}
{{i18n "admin.customize.theme.is_private"}}
</label>
</div>
{{#if showPublicKey}}
<div class="public-key">
<div class="label">{{i18n "admin.customize.theme.public_key"}}</div>
<div class="public-key-text-wrapper">
{{textarea class="public-key-value" readonly=true value=publicKey}}
{{copy-button selector="textarea.public-key-value"}}
</div>
{{#if this.showPublicKey}}
<div class="public-key">
<div class="label">{{i18n "admin.customize.theme.public_key"}}</div>
<div class="public-key-text-wrapper">
<Textarea class="public-key-value" readonly={{true}} @value={{this.publicKey}} />
<CopyButton @selector="textarea.public-key-value" />
</div>
{{else}}
{{#if privateChecked}}
<div class="public-key-note">{{i18n "admin.customize.theme.public_key_note"}}</div>
{{/if}}
{{/if}}
</div>
{{/if}}
</div>
{{/if}}

View File

@ -20,7 +20,7 @@ export function afterRender(target, name, descriptor) {
const originalFunction = descriptor.value;
descriptor.value = function () {
schedule("afterRender", () => {
if (this.element && !this.isDestroying && !this.isDestroyed) {
if (!this.isDestroying && !this.isDestroyed) {
return originalFunction.apply(this, arguments);
}
});

View File

@ -100,6 +100,7 @@ export function cleanUpComposerUploadMarkdownResolver() {
export default Component.extend(ComposerUploadUppy, {
classNameBindings: ["showToolbar:toolbar-visible", ":wmd-controls"],
editorClass: ".d-editor",
fileUploadElementId: "file-uploader",
mobileFileUploaderId: "mobile-file-upload",
eventPrefix: "composer",
@ -199,7 +200,10 @@ export default Component.extend(ComposerUploadUppy, {
@discourseComputed()
acceptsAllFormats() {
return authorizesAllExtensions(this.currentUser.staff, this.siteSettings);
return (
this.capabilities.isIOS ||
authorizesAllExtensions(this.currentUser.staff, this.siteSettings)
);
},
@discourseComputed()

View File

@ -477,7 +477,7 @@ export default Component.extend(TextareaTextManipulation, {
key: "#",
afterComplete: (value) => {
this.set("value", value);
return this._focusTextArea();
schedule("afterRender", this, this._focusTextArea);
},
transformComplete: (obj) => {
return obj.text;
@ -504,7 +504,7 @@ export default Component.extend(TextareaTextManipulation, {
key: ":",
afterComplete: (text) => {
this.set("value", text);
this._focusTextArea();
schedule("afterRender", this, this._focusTextArea);
},
onKeyUp: (text, cp) => {

View File

@ -58,24 +58,6 @@ export default MountWidget.extend({
);
},
beforePatch() {
this.prevHeight = document.body.clientHeight;
this.prevScrollTop = document.body.scrollTop;
},
afterPatch() {
const height = document.body.clientHeight;
// This hack is for when swapping out many cloaked views at once
// when using keyboard navigation. It could suddenly move the scroll
if (
this.prevHeight === height &&
document.body.scrollTop !== this.prevScrollTop
) {
document.body.scroll({ left: 0, top: this.prevScrollTop });
}
},
scrolled() {
if (this.isDestroyed || this.isDestroying) {
return;
@ -103,7 +85,7 @@ export default MountWidget.extend({
const slack = Math.round(windowHeight * 5);
const onscreen = [];
const nearby = [];
const windowTop = document.documentElement.scrollTop;
const windowTop = document.scrollingElement.scrollTop;
const postsWrapperTop = domUtils.offset(
document.querySelector(".posts-wrapper")
).top;
@ -202,9 +184,7 @@ export default MountWidget.extend({
const elem = postsNodes.item(onscreen[0]);
const elemId = elem.id;
const elemPos = domUtils.position(elem);
const distToElement = elemPos
? document.body.scrollTop - elemPos.top
: 0;
const distToElement = elemPos?.top || 0;
const topRefresh = () => {
refresh(() => {
@ -213,7 +193,7 @@ export default MountWidget.extend({
// Quickly going back might mean the element is destroyed
const position = domUtils.position(refreshedElem);
if (position && position.top) {
let whereY = position.top + distToElement;
let whereY = position.top - distToElement;
document.documentElement.scroll({ top: whereY, left: 0 });
// This seems weird, but somewhat infrequently a rerender

View File

@ -4,7 +4,7 @@ import TextField from "discourse/components/text-field";
import { applySearchAutocomplete } from "discourse/lib/search";
export default TextField.extend({
autocomplete: "discourse-search",
autocomplete: "off",
@discourseComputed("searchService.searchContextEnabled")
placeholder(searchContextEnabled) {

View File

@ -441,6 +441,5 @@ export default SiteHeaderComponent.extend({
export function headerTop() {
const header = document.querySelector("header.d-header");
const headerOffsetTop = header.offsetTop ? header.offsetTop : 0;
return headerOffsetTop - document.body.scrollTop;
return header.offsetTop ? header.offsetTop : 0;
}

View File

@ -1,4 +1,4 @@
import { alias, notEmpty, or, readOnly } from "@ember/object/computed";
import { alias, bool, not, readOnly } from "@ember/object/computed";
import Controller, { inject as controller } from "@ember/controller";
import DiscourseURL from "discourse/lib/url";
import EmberObject from "@ember/object";
@ -29,24 +29,23 @@ export default Controller.extend(
invitedBy: readOnly("model.invited_by"),
email: alias("model.email"),
accountEmail: alias("email"),
existingUserId: readOnly("model.existing_user_id"),
existingUserCanRedeem: readOnly("model.existing_user_can_redeem"),
existingUserCanRedeemError: readOnly(
"model.existing_user_can_redeem_error"
),
existingUserRedeeming: bool("existingUserId"),
hiddenEmail: alias("model.hidden_email"),
emailVerifiedByLink: alias("model.email_verified_by_link"),
differentExternalEmail: alias("model.different_external_email"),
accountUsername: alias("model.username"),
passwordRequired: notEmpty("accountPassword"),
passwordRequired: not("externalAuthsOnly"),
successMessage: null,
errorMessage: null,
userFields: null,
authOptions: null,
inviteImageUrl: getUrl("/images/envelope.svg"),
isInviteLink: readOnly("model.is_invite_link"),
submitDisabled: or(
"emailValidation.failed",
"usernameValidation.failed",
"passwordValidation.failed",
"nameValidation.failed",
"userFieldsValidation.failed"
),
rejectedEmails: null,
init() {
@ -81,6 +80,15 @@ export default Controller.extend(
});
},
@discourseComputed("existingUserId")
subheaderMessage(existingUserId) {
if (existingUserId) {
return I18n.t("invites.existing_user_can_redeem");
} else {
return I18n.t("create_account.subheader_title");
}
},
@discourseComputed("email")
yourEmailMessage(email) {
return I18n.t("invites.your_email", { email });
@ -100,21 +108,69 @@ export default Controller.extend(
);
},
@discourseComputed("externalAuthsOnly", "discourseConnectEnabled")
showSocialLoginAvailable(externalAuthsOnly, discourseConnectEnabled) {
return !externalAuthsOnly && !discourseConnectEnabled;
@discourseComputed(
"emailValidation.failed",
"usernameValidation.failed",
"passwordValidation.failed",
"nameValidation.failed",
"userFieldsValidation.failed",
"existingUserRedeeming",
"existingUserCanRedeem"
)
submitDisabled(
emailValidationFailed,
usernameValidationFailed,
passwordValidationFailed,
nameValidationFailed,
userFieldsValidationFailed,
existingUserRedeeming,
existingUserCanRedeem
) {
if (existingUserRedeeming) {
return !existingUserCanRedeem;
}
return (
emailValidationFailed ||
usernameValidationFailed ||
passwordValidationFailed ||
nameValidationFailed ||
userFieldsValidationFailed
);
},
@discourseComputed(
"externalAuthsEnabled",
"externalAuthsOnly",
"discourseConnectEnabled"
)
showSocialLoginAvailable(
externalAuthsEnabled,
externalAuthsOnly,
discourseConnectEnabled
) {
return (
externalAuthsEnabled && !externalAuthsOnly && !discourseConnectEnabled
);
},
@discourseComputed(
"externalAuthsOnly",
"authOptions",
"emailValidation.failed"
"emailValidation.failed",
"existingUserRedeeming"
)
shouldDisplayForm(externalAuthsOnly, authOptions, emailValidationFailed) {
shouldDisplayForm(
externalAuthsOnly,
authOptions,
emailValidationFailed,
existingUserRedeeming
) {
return (
(this.siteSettings.enable_local_logins ||
(externalAuthsOnly && authOptions && !emailValidationFailed)) &&
!this.siteSettings.enable_discourse_connect
!this.siteSettings.enable_discourse_connect &&
!existingUserRedeeming
);
},

View File

@ -1,7 +1,9 @@
import Controller from "@ember/controller";
import { action } from "@ember/object";
import { getAbsoluteURL } from "discourse-common/lib/get-url";
import discourseComputed from "discourse-common/utils/decorators";
import discourseComputed, {
afterRender,
} from "discourse-common/utils/decorators";
import { ajax } from "discourse/lib/ajax";
import { extractError } from "discourse/lib/ajax-error";
import Sharing from "discourse/lib/sharing";
@ -16,14 +18,30 @@ export default Controller.extend(
bufferedProperty("invite"),
{
topic: null,
restrictedGroups: null,
onShow() {
this.set("showNotifyUsers", false);
if (this.model && this.model.read_restricted) {
this.restrictedGroupWarning();
this._showRestrictedGroupWarning();
},
@afterRender
_showRestrictedGroupWarning() {
if (!this.model) {
return;
}
Category.fetchVisibleGroups(this.model.id).then((result) => {
if (result.groups.length > 0) {
this.flash(
I18n.t("topic.share.restricted_groups", {
count: result.groups.length,
groupNames: result.groups.join(", "),
}),
"warning"
);
}
});
},
@discourseComputed("topic.shareUrl")
@ -111,24 +129,5 @@ export default Controller.extend(
topicTitle: this.topic.title,
});
},
restrictedGroupWarning() {
this.appEvents.on("modal:body-shown", () => {
let restrictedGroups;
Category.reloadBySlugPath(this.model.slug).then((result) => {
restrictedGroups = result.category.group_permissions.map(
(g) => g.group_name
);
if (restrictedGroups) {
const message = I18n.t("topic.share.restricted_groups", {
count: restrictedGroups.length,
groupNames: restrictedGroups.join(", "),
});
this.flash(message, "warning");
}
});
});
},
}
);

View File

@ -2,6 +2,7 @@ import User from "discourse/models/user";
import { escapeExpression } from "discourse/lib/utilities";
import getURL from "discourse-common/lib/get-url";
import { helperContext } from "discourse-common/lib/helpers";
import { escape } from "pretty-text/sanitizer";
let _renderer = defaultRenderTag;
@ -44,7 +45,7 @@ export function defaultRenderTag(tag, params) {
href +
" data-tag-name=" +
tag +
(params.description ? ' title="' + params.description + '" ' : "") +
(params.description ? ' title="' + escape(params.description) + '" ' : "") +
" class='" +
classes.join(" ") +
"'>" +

View File

@ -150,7 +150,6 @@ export function excerpt(cooked, length) {
resultLength += element.textContent.length;
}
} else if (element.tagName === "A") {
element.innerHTML = element.innerText;
result += element.outerHTML;
resultLength += element.innerText.length;
} else if (element.tagName === "IMG") {

View File

@ -64,7 +64,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
this.fileInputEventListener
);
this.element.removeEventListener("paste", this.pasteEventListener);
this.editorEl?.removeEventListener("paste", this.pasteEventListener);
this.appEvents.off(`${this.eventPrefix}:add-files`, this._addFiles);
this.appEvents.off(
@ -92,6 +92,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
this.set("inProgressUploads", []);
this.placeholders = {};
this._preProcessorStatus = {};
this.editorEl = this.element.querySelector(this.editorClass);
this.fileInputEl = document.getElementById(this.fileUploadElementId);
const isPrivateMessage = this.get("composerModel.privateMessage");
@ -106,7 +107,7 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
this.fileInputEl,
this._addFiles
);
this.element.addEventListener("paste", this.pasteEventListener);
this.editorEl?.addEventListener("paste", this.pasteEventListener);
this._uppyInstance = new Uppy({
id: this.uppyId,
@ -520,12 +521,12 @@ export default Mixin.create(ExtendableUploader, UppyS3Multipart, {
return;
}
const { canUpload } = clipboardHelpers(event, {
const { canUpload, canPasteHtml, types } = clipboardHelpers(event, {
siteSettings: this.siteSettings,
canUpload: true,
});
if (!canUpload) {
if (!canUpload || canPasteHtml || types.includes("text/plain")) {
return;
}

View File

@ -25,18 +25,16 @@ export default Mixin.create({
// ensures textarea scroll position is correct
_focusTextArea() {
schedule("afterRender", () => {
if (!this.element || this.isDestroying || this.isDestroyed) {
return;
}
if (!this.element || this.isDestroying || this.isDestroyed) {
return;
}
if (!this._textarea) {
return;
}
if (!this._textarea) {
return;
}
this._textarea.blur();
this._textarea.focus();
});
this._textarea.blur();
this._textarea.focus();
},
_insertBlock(text) {
@ -171,7 +169,7 @@ export default Mixin.create({
this._$textarea.prop("selectionStart", (pre + text).length + 2);
this._$textarea.prop("selectionEnd", (pre + text).length + 2);
this._focusTextArea();
schedule("afterRender", this, this._focusTextArea);
},
_addText(sel, text, options) {

View File

@ -519,6 +519,10 @@ Category.reopenClass({
return category;
},
fetchVisibleGroups(id) {
return ajax(`/c/${id}/visible_groups.json`);
},
reloadById(id) {
return ajax(`/c/${id}/show.json`);
},

View File

@ -1,4 +1,6 @@
import DiscourseRoute from "discourse/routes/discourse";
import { emojiUnescape } from "discourse/lib/text";
import { escapeExpression } from "discourse/lib/utilities";
export default DiscourseRoute.extend({
beforeModel() {
@ -6,9 +8,19 @@ export default DiscourseRoute.extend({
},
model() {
return this.store.findAll("pending-post", {
username: this.username,
});
return this.store
.findAll("pending-post", {
username: this.username,
})
.then((pendingPosts) => {
for (let pendingPost of pendingPosts.content) {
pendingPost.title = emojiUnescape(
escapeExpression(pendingPost.title)
);
}
return pendingPosts;
});
},
activate() {

View File

@ -5,7 +5,7 @@
placeholderKey=composer.titlePlaceholder
aria-label=(I18n composer.titlePlaceholder)
disabled=disabled
autocomplete="discourse"
autocomplete="off"
}}
{{popup-input-tip validation=validation}}

View File

@ -43,7 +43,7 @@
{{conditional-loading-spinner condition=loading}}
{{d-textarea
autocomplete="discourse"
autocomplete="off"
tabindex=tabindex
value=value
class="d-editor-input"

View File

@ -24,7 +24,8 @@
class="filter"
name="filter"
placeholder=(i18n "emoji_picker.filter_placeholder")
autocomplete="discourse"
autocomplete="off"
type="search"
autocorrect="off"
autocapitalize="off"
input=(action "onFilter")

View File

@ -4,7 +4,7 @@
{{text-field
value=filterInput
placeholderKey=filterPlaceholder
autocomplete="discourse"
autocomplete="off"
class="group-username-filter no-blur"
}}
{{/if}}

View File

@ -4,7 +4,7 @@
<h1 class="login-title">{{welcomeTitle}}</h1>
<img src={{wavingHandURL}} alt="" class="waving-hand">
{{#unless successMessage}}
<p class="login-subheader">{{i18n "create_account.subheader_title"}}</p>
<p class="login-subheader">{{loginSubheader}}</p>
{{/unless}}
</div>
@ -70,7 +70,7 @@
{{/if}}
<div class="input username-input input-group">
{{input value=accountUsername class=(value-entered accountUsername) id="new-account-username" name="username" maxlength=maxUsernameLength autocomplete="discourse"}}
{{input value=accountUsername class=(value-entered accountUsername) id="new-account-username" name="username" maxlength=maxUsernameLength autocomplete="off"}}
<label class="alt-placeholder" for="new-account-username">
{{i18n "user.username.title"}}
<span class="required">*</span>
@ -132,6 +132,13 @@
{{/if}}
</form>
{{/if}}
{{#if this.existingUserRedeeming}}
{{#if this.existingUserCanRedeem}}
<DButton @class="btn-primary" @action={{action "submit"}} @type="submit" @disabled={{this.submitDisabled}} @label="invites.accept_invite" />
{{else}}
<div class="alert alert-error">{{this.existingUserCanRedeemError}}</div>
{{/if}}
{{/if}}
{{/if}}
</div>
</div>

View File

@ -2,7 +2,7 @@
{{text-field
value=filterInput
placeholderKey=filterPlaceholder
autocomplete="discourse"
autocomplete="off"
class="group-username-filter no-blur"
}}

View File

@ -49,7 +49,7 @@
maxlength=maxUsernameLength
aria-describedby="username-validation"
aria-invalid=usernameValidation.failed
autocomplete="discourse"
autocomplete="off"
}}
<label class="alt-placeholder" for="new-account-username">
{{i18n "user.username.title"}}

View File

@ -12,7 +12,9 @@
value=searchTerm
placeholder=(i18n "bookmarks.search_placeholder")
enter=(action "search")
id="bookmark-search" autocomplete="discourse"}}
id="bookmark-search"
autocomplete="off"
}}
{{d-button
class="btn-primary"
action=(action "search")

View File

@ -104,7 +104,6 @@ module.exports = function (defaults) {
// For example: our very specific version of bootstrap-modal.
app.import(vendorJs + "bootbox.js");
app.import(vendorJs + "bootstrap-modal.js");
app.import(vendorJs + "jquery.ui.widget.js");
app.import(vendorJs + "caret_position.js");
app.import("node_modules/ember-source/dist/ember-template-compiler.js", {
type: "test",

View File

@ -8,7 +8,6 @@ acceptance("Admin - Themes - Install modal", function (needs) {
test("closing the modal resets the modal inputs", async function (assert) {
const urlInput = ".install-theme-content .repo input";
const branchInput = ".install-theme-content .branch input";
const privateRepoCheckbox = ".install-theme-content .check-private input";
const publicKey = ".install-theme-content .public-key textarea";
const themeUrl = "git@github.com:discourse/discourse.git";
@ -19,17 +18,12 @@ acceptance("Admin - Themes - Install modal", function (needs) {
await fillIn(urlInput, themeUrl);
await click(".install-theme-content .inputs .advanced-repo");
await fillIn(branchInput, "tests-passed");
await click(privateRepoCheckbox);
assert.strictEqual(query(urlInput).value, themeUrl, "url input is filled");
assert.strictEqual(
query(branchInput).value,
"tests-passed",
"branch input is filled"
);
assert.ok(
query(privateRepoCheckbox).checked,
"private repo checkbox is checked"
);
assert.ok(query(publicKey), "shows public key");
await click(".modal-footer .d-modal-cancel");
@ -38,16 +32,11 @@ acceptance("Admin - Themes - Install modal", function (needs) {
await click("#remote");
assert.strictEqual(query(urlInput).value, "", "url input is reset");
assert.strictEqual(query(branchInput).value, "", "branch input is reset");
assert.ok(
!query(privateRepoCheckbox).checked,
"private repo checkbox unchecked"
);
assert.notOk(query(publicKey), "hide public key");
});
test("show public key for valid ssh theme urls", async function (assert) {
const urlInput = ".install-theme-content .repo input";
const privateRepoCheckbox = ".install-theme-content .check-private input";
const publicKey = ".install-theme-content .public-key textarea";
// Supports backlog repo ssh url format
@ -59,12 +48,7 @@ acceptance("Admin - Themes - Install modal", function (needs) {
await click("#remote");
await fillIn(urlInput, themeUrl);
await click(".install-theme-content .inputs .advanced-repo");
await click(privateRepoCheckbox);
assert.strictEqual(query(urlInput).value, themeUrl, "url input is filled");
assert.ok(
query(privateRepoCheckbox).checked,
"private repo checkbox is checked"
);
assert.ok(query(publicKey), "shows public key");
// Supports AWS CodeCommit style repo URLs

View File

@ -2,12 +2,13 @@ import {
acceptance,
createFile,
loggedInUser,
paste,
query,
} from "discourse/tests/helpers/qunit-helpers";
import { withPluginApi } from "discourse/lib/plugin-api";
import bootbox from "bootbox";
import { authorizedExtensions } from "discourse/lib/uploads";
import { click, fillIn, visit } from "@ember/test-helpers";
import { click, fillIn, settled, visit } from "@ember/test-helpers";
import I18n from "I18n";
import { skip, test } from "qunit";
@ -52,6 +53,7 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) {
needs.pretender(pretender);
needs.settings({
simultaneous_uploads: 2,
enable_rich_text_paste: true,
});
test("should insert the Uploading placeholder then the complete image placeholder", async function (assert) {
@ -313,6 +315,64 @@ acceptance("Uppy Composer Attachment - Upload Placeholder", function (needs) {
const image = createFile("avatar.png");
appEvents.trigger("composer:add-files", image);
});
skip("should place cursor properly after inserting a placeholder", async function (assert) {
const appEvents = loggedInUser().appEvents;
const done = assert.async();
await visit("/");
await click("#create-topic");
await fillIn(".d-editor-input", "The image:\ntext after image");
const input = query(".d-editor-input");
input.selectionStart = 10;
input.selectionEnd = 10;
appEvents.on("composer:all-uploads-complete", () => {
// after uploading we have this in the textarea:
// "The image:\n![avatar.PNG|690x320](upload://yoj8pf9DdIeHRRULyw7i57GAYdz.jpeg)\ntext after image"
// cursor should be just before "text after image":
assert.equal(input.selectionStart, 76);
assert.equal(input.selectionEnd, 76);
done();
});
const image = createFile("avatar.png");
appEvents.trigger("composer:add-files", image);
});
test("should be able to paste a table with files and not upload the files", async function (assert) {
await visit("/");
await click("#create-topic");
const appEvents = loggedInUser().appEvents;
const done = assert.async();
let uppyEventFired = false;
appEvents.on("composer:upload-started", () => {
uppyEventFired = true;
});
let element = query(".d-editor");
let inputElement = query(".d-editor-input");
inputElement.focus();
await paste(element, "\ta\tb\n1\t2\t3", {
types: ["text/plain", "Files"],
files: [createFile("avatar.png")],
});
await settled();
assert.strictEqual(
inputElement.value,
"||a|b|\n|---|---|---|\n|1|2|3|\n",
"only the plain text table is pasted"
);
assert.strictEqual(
uppyEventFired,
false,
"uppy does not start uploading the file"
);
done();
});
});
acceptance("Uppy Composer Attachment - Upload Error", function (needs) {

View File

@ -119,7 +119,13 @@ acceptance("Invite accept", function (needs) {
);
await fillIn("#new-account-email", "john.doe@example.com");
assert.not(
assert.ok(
exists(".invites-show .btn-primary:disabled"),
"submit is disabled because password is not filled"
);
await fillIn("#new-account-password", "top$ecret");
assert.notOk(
exists(".invites-show .btn-primary:disabled"),
"submit is enabled"
);

View File

@ -1,8 +1,11 @@
import CategoryFixtures from "discourse/tests/fixtures/category-fixtures";
import I18n from "I18n";
import { click, visit } from "@ember/test-helpers";
import {
acceptance,
count,
exists,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
import selectKit from "discourse/tests/helpers/select-kit-helper";
@ -11,6 +14,20 @@ import { test } from "qunit";
acceptance("Share and Invite modal", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get(`/c/2481/visible_groups.json`, () =>
helper.response(200, {
groups: ["group_name_1", "group_name_2"],
})
);
server.get(`/c/2/visible_groups.json`, () =>
helper.response(200, {
groups: [],
})
);
});
test("Topic footer button", async function (assert) {
await visit("/t/internationalization-localization/280");
@ -23,6 +40,11 @@ acceptance("Share and Invite modal", function (needs) {
assert.ok(exists(".share-topic-modal"), "it shows the modal");
assert.notOk(
exists("#modal-alert.alert-warning"),
"it does not show the alert with restricted groups"
);
assert.ok(
queryAll("input.invite-link")
.val()
@ -64,6 +86,14 @@ acceptance("Share and Invite modal", function (needs) {
exists("#modal-alert.alert-warning"),
"it shows restricted warning"
);
assert.strictEqual(
query("#modal-alert.alert-warning").innerText,
I18n.t("topic.share.restricted_groups", {
count: 2,
groupNames: "group_name_1, group_name_2",
}),
"it shows correct restricted group name"
);
});
});
@ -90,6 +120,13 @@ acceptance("Share and Invite modal - mobile", function (needs) {
acceptance("Share url with badges disabled - desktop", function (needs) {
needs.user();
needs.settings({ enable_badges: false });
needs.pretender((server, helper) => {
server.get("/c/feature/find_by_slug.json", () =>
helper.response(200, CategoryFixtures["/c/1/show.json"])
);
});
test("topic footer button - badges disabled - desktop", async function (assert) {
await visit("/t/internationalization-localization/280");
await click("#topic-footer-button-share-and-invite");

View File

@ -20,10 +20,20 @@ import { skip, test } from "qunit";
import { withPluginApi } from "discourse/lib/plugin-api";
import topicFixtures from "discourse/tests/fixtures/topic";
import { cloneJSON } from "discourse-common/lib/object";
import CategoryFixtures from "discourse/tests/fixtures/category-fixtures";
acceptance("Topic", function (needs) {
needs.user();
needs.pretender((server, helper) => {
server.get("/c/2/visible_groups.json", () =>
helper.response(200, {
groups: [],
})
);
server.get("/c/feature/find_by_slug.json", () => {
return helper.response(200, CategoryFixtures["/c/1/show.json"]);
});
server.put("/posts/398/wiki", () => {
return helper.response({});
});

View File

@ -1117,6 +1117,8 @@ export function applyDefaultHandlers(pretender) {
],
});
});
pretender.get("/c/:id/visible_groups.json", () => response({ groups: [] }));
}
export function resetPretender() {

View File

@ -1,4 +1,5 @@
import QUnit, { module, skip, test } from "qunit";
import { deepMerge } from "discourse-common/lib/object";
import MessageBus from "message-bus-client";
import {
clearCache as clearOutletCache,
@ -561,3 +562,11 @@ export function createFile(name, type = "image/png", blobData = null) {
});
return file;
}
export async function paste(element, text, otherClipboardData = {}) {
let e = new Event("paste", { cancelable: true });
e.clipboardData = deepMerge({ getData: () => text }, otherClipboardData);
element.dispatchEvent(e);
await settled();
return e;
}

View File

@ -5,6 +5,7 @@ import componentTest, {
import {
discourseModule,
exists,
paste,
query,
queryAll,
} from "discourse/tests/helpers/qunit-helpers";
@ -822,14 +823,6 @@ third line`
}
);
async function paste(element, text) {
let e = new Event("paste", { cancelable: true });
e.clipboardData = { getData: () => text };
element.dispatchEvent(e);
await settled();
return e;
}
componentTest("paste table", {
template: hbs`{{d-editor value=value composerEvents=true}}`,
beforeEach() {

View File

@ -0,0 +1,27 @@
import { module, test } from "qunit";
import { cookAsync, excerpt } from "discourse/lib/text";
module("Unit | Utility | text", function () {
test("excerpt", async function (assert) {
let cooked = await cookAsync("Hello! :wave:");
assert.strictEqual(
await excerpt(cooked, 300),
'Hello! <img src="/images/emoji/google_classic/wave.png?v=12" title=":wave:" class="emoji" alt=":wave:" loading="lazy" width="20" height="20">'
);
cooked = await cookAsync("[:wave:](https://example.com)");
assert.strictEqual(
await excerpt(cooked, 300),
'<a href="https://example.com"><img src="/images/emoji/google_classic/wave.png?v=12" title=":wave:" class="emoji only-emoji" alt=":wave:" loading="lazy" width="20" height="20"></a>'
);
cooked = await cookAsync('<script>alert("hi")</script>');
assert.strictEqual(await excerpt(cooked, 300), "");
cooked = await cookAsync("[`<script>alert('hi')</script>`]()");
assert.strictEqual(
await excerpt(cooked, 300),
"<a><code>&lt;script&gt;alert('hi')&lt;/script&gt;</code></a>"
);
});
});

View File

@ -4,7 +4,7 @@
tabindex=0
class="filter-input"
placeholder=placeholder
autocomplete="discourse"
autocomplete="off"
autocorrect="off"
autocapitalize="off"
name="filter-input-search"
@ -14,6 +14,7 @@
paste=(action "onPaste")
keyDown=(action "onKeydown")
keyUp=(action "onKeyup")
type="search"
}}
{{#if selectKit.options.filterIcon}}

View File

@ -4,7 +4,7 @@
{{yield}}
{{else}}
<span class="d-button-label">
{{html-safe itemName}}
{{itemName}}
</span>
{{/if}}
</button>

View File

@ -3,13 +3,11 @@
//= require template_include.js
//= require message-bus
//= require jquery.ui.widget.js
//= require Markdown.Converter.js
//= require bootbox.js
//= require popper.js
//= require bootstrap-modal.js
//= require caret_position
//= require jquery.sortable.js
//= require lodash.js
//= require itsatrap.js
//= require rsvp.js

View File

@ -1,6 +1,5 @@
//= require ember_jquery
//= require template_include.js
//= require jquery.ui.widget.js
//= require uppy.js
//= require bootstrap-modal.js
//= require bootbox.js

View File

@ -49,6 +49,13 @@ let createPretendServer = requirejs(
).default;
let server;
const queryParams = new URLSearchParams(window.location.search);
if (queryParams.get("qunit_disable_auto_start") === "1") {
QUnit.config.autostart = false;
}
QUnit.testStart(function () {
server = createPretendServer();
});

View File

@ -230,6 +230,14 @@ input {
}
}
input[type="search"] {
&::-webkit-search-cancel-button,
&::-webkit-search-decoration {
-webkit-appearance: none;
appearance: none;
}
}
// Fixes Safari height inconsistency
::-webkit-datetime-edit {
display: inline;

View File

@ -5,6 +5,7 @@ require 'base64'
class Admin::ThemesController < Admin::AdminController
skip_before_action :check_xhr, only: [:show, :preview, :export]
before_action :ensure_admin
def preview
theme = Theme.find_by(id: params[:id])
@ -101,8 +102,11 @@ class Admin::ThemesController < Admin::AdminController
begin
branch = params[:branch] ? params[:branch] : nil
@theme = RemoteTheme.import_theme(remote, theme_user, private_key: params[:private_key], branch: branch)
render json: @theme, status: :created
hijack do
@theme = RemoteTheme.import_theme(remote, theme_user, private_key: params[:private_key], branch: branch)
render json: @theme, status: :created
end
rescue RemoteTheme::ImportError => e
render_json_error e.message
end

View File

@ -84,22 +84,12 @@ class Admin::WebHooksController < Admin::AdminController
end
def redeliver_event
web_hook_event = WebHookEvent.find(params[:event_id])
web_hook_event = WebHookEvent.find_by(id: params[:event_id])
if web_hook_event
web_hook = web_hook_event.web_hook
conn = Excon.new(URI(web_hook.payload_url).to_s,
ssl_verify_peer: web_hook.verify_certificate,
retry_limit: 0)
now = Time.zone.now
response = conn.post(headers: MultiJson.load(web_hook_event.headers), body: web_hook_event.payload)
web_hook_event.update!(
status: response.status,
response_headers: MultiJson.dump(response.headers),
response_body: response.body,
duration: ((Time.zone.now - now) * 1000).to_i
)
emitter = WebHookEmitter.new(web_hook, web_hook_event)
emitter.emit!(headers: MultiJson.load(web_hook_event.headers), body: web_hook_event.payload)
render_serialized(web_hook_event, AdminWebHookEventSerializer, root: 'web_hook_event')
else
render json: failed_json

View File

@ -642,6 +642,7 @@ class ApplicationController < ActionController::Base
def banner_json
json = ApplicationController.banner_json_cache["json"]
return "{}" if !current_user && SiteSetting.login_required?
unless json
topic = Topic.where(archetype: Archetype.banner).first

View File

@ -2,9 +2,9 @@
class CategoriesController < ApplicationController
requires_login except: [:index, :categories_and_latest, :categories_and_top, :show, :redirect, :find_by_slug]
requires_login except: [:index, :categories_and_latest, :categories_and_top, :show, :redirect, :find_by_slug, :visible_groups]
before_action :fetch_category, only: [:show, :update, :destroy]
before_action :fetch_category, only: [:show, :update, :destroy, :visible_groups]
before_action :initialize_staff_action_logger, only: [:create, :update, :destroy]
skip_before_action :check_xhr, only: [:index, :categories_and_latest, :categories_and_top, :redirect]
@ -117,6 +117,7 @@ class CategoriesController < ApplicationController
if Category.topic_create_allowed(guardian).where(id: @category.id).exists?
@category.permission = CategoryGroup.permission_types[:full]
end
render_serialized(@category, CategorySerializer)
end
@ -249,6 +250,11 @@ class CategoriesController < ApplicationController
render_serialized(@category, CategorySerializer)
end
def visible_groups
@guardian.ensure_can_see!(@category)
render json: success_json.merge(groups: @category.groups.merge(Group.visible_groups(current_user)).pluck("name"))
end
private
def self.topics_per_page
@ -365,6 +371,7 @@ class CategoriesController < ApplicationController
def fetch_category
@category = Category.find_by_slug(params[:id]) || Category.find_by(id: params[:id].to_i)
raise Discourse::NotFound if @category.blank?
end
def initialize_staff_action_logger

View File

@ -12,7 +12,6 @@ class InvitesController < ApplicationController
before_action :ensure_invites_allowed, only: [:show, :perform_accept_invitation]
before_action :ensure_new_registrations_allowed, only: [:show, :perform_accept_invitation]
before_action :ensure_not_logged_in, only: :perform_accept_invitation
def show
expires_now
@ -20,98 +19,11 @@ class InvitesController < ApplicationController
RateLimiter.new(nil, "invites-show-#{request.remote_ip}", 100, 1.minute).performed!
invite = Invite.find_by(invite_key: params[:id])
if invite.present? && invite.redeemable?
if current_user
added_to_group = false
if invite.groups.present?
invite_by_guardian = Guardian.new(invite.invited_by)
new_group_ids = invite.groups.pluck(:id) - current_user.group_users.pluck(:group_id)
new_group_ids.each do |id|
if group = Group.find_by(id: id)
if invite_by_guardian.can_edit_group?(group)
group.add(current_user)
added_to_group = true
end
end
end
end
create_topic_invite_notifications(invite, current_user)
if topic = invite.topics.first
new_guardian = Guardian.new(current_user)
return redirect_to(topic.url) if new_guardian.can_see?(topic)
elsif added_to_group
return redirect_to(path("/"))
end
return ensure_not_logged_in
end
email = Email.obfuscate(invite.email)
# Show email if the user already authenticated their email
different_external_email = false
if session[:authentication]
auth_result = Auth::Result.from_session_data(session[:authentication], user: nil)
if invite.email == auth_result.email
email = invite.email
else
different_external_email = true
end
end
email_verified_by_link = invite.email_token.present? && params[:t] == invite.email_token
if email_verified_by_link
email = invite.email
end
hidden_email = email != invite.email
if hidden_email || invite.email.nil?
username = ""
else
username = UserNameSuggester.suggest(invite.email)
end
info = {
invited_by: UserNameSerializer.new(invite.invited_by, scope: guardian, root: false),
email: email,
hidden_email: hidden_email,
username: username,
is_invite_link: invite.is_invite_link?,
email_verified_by_link: email_verified_by_link
}
if different_external_email
info[:different_external_email] = true
end
if staged_user = User.where(staged: true).with_email(invite.email).first
info[:username] = staged_user.username
info[:user_fields] = staged_user.user_fields
end
store_preloaded("invite_info", MultiJson.dump(info))
secure_session["invite-key"] = invite.invite_key
render layout: 'application'
show_invite(invite)
else
flash.now[:error] = if invite.blank?
I18n.t('invite.not_found', base_url: Discourse.base_url)
elsif invite.redeemed?
if invite.is_invite_link?
I18n.t('invite.not_found_template_link', site_name: SiteSetting.title, base_url: Discourse.base_url)
else
I18n.t('invite.not_found_template', site_name: SiteSetting.title, base_url: Discourse.base_url)
end
elsif invite.expired?
I18n.t('invite.expired', base_url: Discourse.base_url)
end
render layout: 'no_ember'
show_irredeemable_invite(invite)
end
rescue RateLimiter::LimitExceeded => e
flash.now[:error] = e.description
@ -272,24 +184,33 @@ class InvitesController < ApplicationController
params.permit(:email, :username, :name, :password, :timezone, :email_token, user_custom_fields: {})
invite = Invite.find_by(invite_key: params[:id])
redeeming_user = current_user
if invite.present?
begin
attrs = {
username: params[:username],
name: params[:name],
password: params[:password],
user_custom_fields: params[:user_custom_fields],
ip_address: request.remote_ip,
session: session
}
if invite.is_invite_link?
params.require(:email)
attrs[:email] = params[:email]
if redeeming_user
attrs[:redeeming_user] = redeeming_user
else
attrs[:email] = invite.email
attrs[:email_token] = params[:email_token] if params[:email_token].present?
attrs[:username] = params[:username]
attrs[:name] = params[:name]
attrs[:password] = params[:password]
attrs[:user_custom_fields] = params[:user_custom_fields]
# If the invite is not scoped to an email then we allow the
# user to provide it themselves
if invite.is_invite_link?
params.require(:email)
attrs[:email] = params[:email]
else
# Otherwise we always use the email from the invitation.
attrs[:email] = invite.email
attrs[:email_token] = params[:email_token] if params[:email_token].present?
end
end
user = invite.redeem(**attrs)
@ -301,7 +222,10 @@ class InvitesController < ApplicationController
return render json: failed_json.merge(message: I18n.t('invite.not_found_json')), status: 404
end
log_on_user(user) if user.active? && user.guardian.can_access_forum?
if !redeeming_user && user.active? && user.guardian.can_access_forum?
log_on_user(user)
end
user.update_timezone_if_missing(params[:timezone])
post_process_invite(user)
create_topic_invite_notifications(invite, user)
@ -311,6 +235,10 @@ class InvitesController < ApplicationController
if user.present?
if user.active? && user.guardian.can_access_forum?
if redeeming_user
response[:message] = I18n.t("invite.existing_user_success")
end
if user.guardian.can_see?(topic)
response[:redirect_to] = path(topic.relative_url)
else
@ -413,6 +341,85 @@ class InvitesController < ApplicationController
private
def show_invite(invite)
email = Email.obfuscate(invite.email)
# Show email if the user already authenticated their email
different_external_email = false
if session[:authentication]
auth_result = Auth::Result.from_session_data(session[:authentication], user: nil)
if invite.email == auth_result.email
email = invite.email
else
different_external_email = true
end
end
email_verified_by_link = invite.email_token.present? && params[:t] == invite.email_token
if email_verified_by_link
email = invite.email
end
hidden_email = email != invite.email
if hidden_email || invite.email.nil?
username = ""
else
username = UserNameSuggester.suggest(invite.email)
end
info = {
invited_by: UserNameSerializer.new(invite.invited_by, scope: guardian, root: false),
email: email,
hidden_email: hidden_email,
username: username,
is_invite_link: invite.is_invite_link?,
email_verified_by_link: email_verified_by_link
}
if different_external_email
info[:different_external_email] = true
end
if staged_user = User.where(staged: true).with_email(invite.email).first
info[:username] = staged_user.username
info[:user_fields] = staged_user.user_fields
end
if current_user
info[:existing_user_id] = current_user.id
info[:existing_user_can_redeem] = invite.can_be_redeemed_by?(current_user)
info[:existing_user_can_redeem_error] = existing_user_can_redeem_error(invite)
info[:email] = current_user.email
info[:username] = current_user.username
end
store_preloaded("invite_info", MultiJson.dump(info))
secure_session["invite-key"] = invite.invite_key
render layout: 'application'
end
def show_irredeemable_invite(invite)
flash.now[:error] = \
if invite.blank?
I18n.t('invite.not_found', base_url: Discourse.base_url)
elsif invite.redeemed?
if invite.is_invite_link?
I18n.t('invite.not_found_template_link', site_name: SiteSetting.title, base_url: Discourse.base_url)
else
I18n.t('invite.not_found_template', site_name: SiteSetting.title, base_url: Discourse.base_url)
end
elsif invite.expired?
I18n.t('invite.expired', base_url: Discourse.base_url)
end
render layout: 'no_ember'
end
def ensure_invites_allowed
if (!SiteSetting.enable_local_logins && Discourse.enabled_auth_providers.count == 0 && !SiteSetting.enable_discourse_connect)
raise Discourse::NotFound
@ -427,14 +434,6 @@ class InvitesController < ApplicationController
end
end
def ensure_not_logged_in
if current_user
flash[:error] = I18n.t("login.already_logged_in")
render layout: 'no_ember'
false
end
end
def post_process_invite(user)
user.enqueue_welcome_message('welcome_invite') if user.send_welcome_message
@ -469,4 +468,13 @@ class InvitesController < ApplicationController
end
end
end
def existing_user_can_redeem_error(invite)
return if invite.can_be_redeemed_by?(current_user)
if invite.invited_users.exists?(user: current_user)
I18n.t("invite.existing_user_already_redemeed")
else
I18n.t("invite.existing_user_cannot_redeem")
end
end
end

View File

@ -23,6 +23,7 @@ class NotificationsController < ApplicationController
limit = 50 if limit > 50
notifications = Notification.recent_report(current_user, limit)
notifications = filter_inaccessible_notifications(notifications)
changed = false
if notifications.present? && !(params.has_key?(:silent) || @readonly_mode)
@ -50,6 +51,7 @@ class NotificationsController < ApplicationController
total_rows = notifications.dup.count
notifications = notifications.offset(offset).limit(60)
notifications = filter_inaccessible_notifications(notifications)
render_json_dump(notifications: serialize_data(notifications, NotificationSerializer),
total_rows_notifications: total_rows,
seen_notification_id: user.seen_notification_id,
@ -101,4 +103,9 @@ class NotificationsController < ApplicationController
render_json_dump(NotificationSerializer.new(@notification, scope: guardian, root: false))
end
def filter_inaccessible_notifications(notifications)
topic_ids = notifications.map { |n| n.topic_id }.compact.uniq
accessible_topic_ids = guardian.can_see_topic_ids(topic_ids: topic_ids)
notifications.select { |n| n.topic_id.blank? || accessible_topic_ids.include?(n.topic_id) }
end
end

View File

@ -181,9 +181,11 @@ class SessionController < ApplicationController
return
end
# users logging in via SSO using an invite do not need to be approved,
# they are already pre-approved because they have been invited
if SiteSetting.must_approve_users? && !user.approved? && invite.blank?
if SiteSetting.must_approve_users? && !user.approved?
if invite.present? && user.invited_user.blank?
redeem_invitation(invite, sso, user)
end
if SiteSetting.discourse_connect_not_approved_url.present?
redirect_to SiteSetting.discourse_connect_not_approved_url
else
@ -195,7 +197,7 @@ class SessionController < ApplicationController
# the user has not already redeemed an invite
# (covers the same SSO user visiting an invite link)
elsif invite.present? && user.invited_user.blank?
redeem_invitation(invite, sso)
redeem_invitation(invite, sso, user)
# we directly call user.activate here instead of going
# through the UserActivator path because we assume the account
@ -646,7 +648,7 @@ class SessionController < ApplicationController
end
if invite.redeemable?
if !invite.is_invite_link? && sso.email != invite.email
if invite.is_email_invite? && sso.email != invite.email
raise Invite::ValidationFailed.new(I18n.t("invite.not_matching_email"))
end
elsif invite.expired?
@ -658,14 +660,15 @@ class SessionController < ApplicationController
invite
end
def redeem_invitation(invite, sso)
def redeem_invitation(invite, sso, redeeming_user)
InviteRedeemer.new(
invite: invite,
username: sso.username,
name: sso.name,
ip_address: request.remote_ip,
session: session,
email: sso.email
email: sso.email,
redeeming_user: redeeming_user
).redeem
secure_session["invite-key"] = nil

View File

@ -24,11 +24,19 @@ class UserBadgesController < ApplicationController
user_badges = user_badges.offset(offset.to_i)
end
user_badges_topic_ids = user_badges.map { |user_badge| user_badge.post&.topic_id }.compact
user_badges = UserBadges.new(user_badges: user_badges,
username: params[:username],
grant_count: grant_count)
render_serialized(user_badges, UserBadgesSerializer, root: :user_badge_info, include_long_description: true)
render_serialized(
user_badges,
UserBadgesSerializer,
root: :user_badge_info,
include_long_description: true,
allowed_user_badge_topic_ids: guardian.can_see_topic_ids(topic_ids: user_badges_topic_ids)
)
end
def username
@ -46,9 +54,12 @@ class UserBadgesController < ApplicationController
.includes(post: :topic)
.includes(:granted_by)
user_badges_topic_ids = user_badges.map { |user_badge| user_badge.post&.topic_id }.compact
render_serialized(
user_badges,
DetailedUserBadgeSerializer,
allowed_user_badge_topic_ids: guardian.can_see_topic_ids(topic_ids: user_badges_topic_ids),
root: :user_badges,
)
end

View File

@ -69,7 +69,7 @@ class UsersController < ApplicationController
user_serializer = serializer_class.new(@user, scope: guardian, root: 'user')
topic_id = params[:include_post_count_for].to_i
if topic_id != 0
if topic_id != 0 && guardian.can_see?(Topic.find_by_id(topic_id))
user_serializer.topic_post_count = { topic_id => Post.secured(guardian).where(topic_id: topic_id, user_id: @user.id).count }
end
else
@ -1062,10 +1062,12 @@ class UsersController < ApplicationController
RateLimiter.new(nil, "activate-edit-email-hr-#{request.remote_ip}", 5, 1.hour).performed!
if params[:username].present?
RateLimiter.new(nil, "activate-edit-email-hr-username-#{params[:username]}", 5, 1.hour).performed!
@user = User.find_by_username_or_email(params[:username])
raise Discourse::InvalidAccess.new unless @user.present?
raise Discourse::InvalidAccess.new unless @user.confirm_password?(params[:password])
elsif user_key = session[SessionController::ACTIVATE_USER_KEY]
RateLimiter.new(nil, "activate-edit-email-hr-user-key-#{user_key}", 5, 1.hour).performed!
@user = User.where(id: user_key.to_i).first
end

View File

@ -9,7 +9,6 @@ module Jobs
PING_EVENT = 'ping'
MAX_RETRY_COUNT = 4
RETRY_BACKOFF = 5
REQUEST_TIMEOUT = 20
def execute(args)
@arguments = args
@ -43,39 +42,13 @@ module Jobs
end
def send_webhook!
uri = URI(@web_hook.payload_url.strip)
conn = Excon.new(
uri.to_s,
ssl_verify_peer: @web_hook.verify_certificate,
retry_limit: 0,
write_timeout: REQUEST_TIMEOUT,
read_timeout: REQUEST_TIMEOUT,
connect_timeout: REQUEST_TIMEOUT
)
web_hook_body = build_webhook_body
web_hook_event = create_webhook_event(web_hook_body)
uri = URI(@web_hook.payload_url.strip)
web_hook_headers = build_webhook_headers(uri, web_hook_body, web_hook_event)
web_hook_response = nil
begin
now = Time.zone.now
web_hook_response = conn.post(headers: web_hook_headers, body: web_hook_body)
web_hook_event.update!(
headers: MultiJson.dump(web_hook_headers),
status: web_hook_response.status,
response_headers: MultiJson.dump(web_hook_response.headers),
response_body: web_hook_response.body,
duration: ((Time.zone.now - now) * 1000).to_i
)
rescue => e
web_hook_event.update!(
headers: MultiJson.dump(web_hook_headers),
status: -1,
response_headers: MultiJson.dump(error: e),
duration: ((Time.zone.now - now) * 1000).to_i
)
end
emitter = WebHookEmitter.new(@web_hook, web_hook_event)
web_hook_response = emitter.emit!(headers: web_hook_headers, body: web_hook_body)
publish_webhook_event(web_hook_event)
process_webhook_response(web_hook_response)
@ -151,12 +124,12 @@ module Jobs
headers = {
'Accept' => '*/*',
'Connection' => 'close',
'Content-Length' => web_hook_body.bytesize,
'Content-Length' => web_hook_body.bytesize.to_s,
'Content-Type' => content_type,
'Host' => uri.host,
'User-Agent' => "Discourse/#{Discourse::VERSION::STRING}",
'X-Discourse-Instance' => Discourse.base_url,
'X-Discourse-Event-Id' => web_hook_event.id,
'X-Discourse-Event-Id' => web_hook_event.id.to_s,
'X-Discourse-Event-Type' => @arguments[:event_type]
}

View File

@ -261,15 +261,16 @@ module Jobs
CategoryUser
.where(user_id: @current_user.id)
.select(:category_id, :notification_level, :last_seen_at)
.includes(:category)
.merge(Category.secured(guardian))
.each do |cu|
yield [
cu.category_id,
piped_category_name(cu.category_id),
NotificationLevels.all[cu.notification_level],
cu.last_seen_at
]
end
yield [
cu.category_id,
piped_category_name(cu.category_id, cu.category),
NotificationLevels.all[cu.notification_level],
cu.last_seen_at
]
end
end
def flags_export
@ -408,10 +409,9 @@ module Jobs
@guardian ||= Guardian.new(@current_user)
end
def piped_category_name(category_id)
return "-" unless category_id
category = Category.find_by(id: category_id)
return "#{category_id}" unless category
def piped_category_name(category_id, category)
return "#{category_id}" if category_id && !category
return "-" if !guardian.can_see_category?(category)
categories = [category.name]
while category.parent_category_id && category = category.parent_category
categories << category.name
@ -433,10 +433,10 @@ module Jobs
user_archive_array = []
topic_data = user_archive.topic
user_archive = user_archive.as_json
topic_data = Topic.with_deleted.find_by(id: user_archive['topic_id']) if topic_data.nil?
topic_data = Topic.with_deleted.includes(:category).find_by(id: user_archive['topic_id']) if topic_data.nil?
return user_archive_array if topic_data.nil?
categories = piped_category_name(topic_data.category_id)
categories = piped_category_name(topic_data.category_id, topic_data.category)
is_pm = topic_data.archetype == "private_message" ? I18n.t("csv_export.boolean_yes") : I18n.t("csv_export.boolean_no")
url = "#{Discourse.base_url}/t/#{topic_data.slug}/#{topic_data.id}/#{user_archive['post_number']}"

View File

@ -46,6 +46,12 @@ module Jobs
cc.match(EmailValidator.email_regex) ? cc : nil
end.compact
# Mask the email addresses of non-staged users so
# they are not revealed unnecessarily when we are sending
# the email notification out.
bcc_addresses = User.not_staged.with_email(cc_addresses).pluck(:email)
cc_addresses = cc_addresses - bcc_addresses
# There is a rare race condition causing the Imap::Sync class to create
# an incoming email and associated post/topic, which then kicks off
# the PostAlerter to notify others in the PM about a reply in the topic,
@ -68,7 +74,13 @@ module Jobs
# The EmailLog record created by the sender will have the raw email
# stored, the group smtp ID, and any cc addresses recorded for later
# cross referencing.
message = GroupSmtpMailer.send_mail(group, email, post, cc_addresses)
message = GroupSmtpMailer.send_mail(
group,
email,
post,
cc_addresses: cc_addresses,
bcc_addresses: bcc_addresses
)
Email::Sender.new(message, :group_smtp, recipient_user).send
# Create an incoming email record to avoid importing again from IMAP

View File

@ -5,7 +5,7 @@ require_dependency 'email/message_builder'
class GroupSmtpMailer < ActionMailer::Base
include Email::BuildEmailHelper
def send_mail(from_group, to_address, post, cc_addresses = nil)
def send_mail(from_group, to_address, post, cc_addresses: nil, bcc_addresses: nil)
raise 'SMTP is disabled' if !SiteSetting.enable_smtp
op_incoming_email = post.topic.first_post.incoming_email
@ -51,7 +51,8 @@ class GroupSmtpMailer < ActionMailer::Base
from: from_group.email_username,
from_alias: I18n.t('email_from_without_site', user_name: group_name),
html_override: html_override(post),
cc: cc_addresses
cc: cc_addresses,
bcc: bcc_addresses
)
end

View File

@ -529,11 +529,13 @@ class UserNotifications < ActionMailer::Base
# tag names
if opts[:show_tags_in_subject] && post.topic_id
tags = Tag.joins(:topic_tags)
.where("topic_tags.topic_id = ?", post.topic_id)
.limit(3)
.pluck(:name)
tags =
DiscourseTagging
.visible_tags(Guardian.new(user))
.joins(:topic_tags)
.where("topic_tags.topic_id = ?", post.topic_id)
.limit(3)
.pluck(:name)
show_tags_in_subject = tags.any? ? tags.join(" ") : nil
end

View File

@ -132,6 +132,7 @@ end
# cc_user_ids :integer is an Array
# raw :text
# topic_id :integer
# bcc_addresses :text
#
# Indexes
#

View File

@ -69,7 +69,7 @@ class EmailToken < ActiveRecord::Base
user.create_reviewable if !skip_reviewable
user.set_automatic_groups
DiscourseEvent.trigger(:user_confirmed_email, user)
Invite.redeem_from_email(user.email)
Invite.redeem_for_existing_user(user)
user.reload
end

View File

@ -141,7 +141,7 @@ class Group < ActiveRecord::Base
scope :with_smtp_configured, -> { where(smtp_enabled: true) }
scope :visible_groups, Proc.new { |user, order, opts|
groups = self.order(order || "name ASC")
groups = self.order(order || "groups.name ASC")
if !opts || !opts[:include_everyone]
groups = groups.where("groups.id > 0")

View File

@ -66,14 +66,26 @@ class Invite < ActiveRecord::Base
end
end
# Even if a domain is specified on the invite, it still counts as
# an invite link.
def is_invite_link?
email.blank?
self.email.blank?
end
# Email invites have specific behaviour and it's easier to visually
# parse is_email_invite? than !is_invite_link?
def is_email_invite?
self.email.present?
end
def redeemable?
!redeemed? && !expired? && !deleted_at? && !destroyed? && link_valid?
end
def redeemed_by_user?(redeeming_user)
self.invited_users.exists?(user: redeeming_user)
end
def redeemed?
if is_invite_link?
redemption_count >= max_redemptions_allowed
@ -82,6 +94,23 @@ class Invite < ActiveRecord::Base
end
end
def email_matches?(email)
email.downcase == self.email.downcase
end
def domain_matches?(email)
_, domain = email.split('@')
self.domain == domain
end
def can_be_redeemed_by?(user)
return false if !self.redeemable?
return false if redeemed_by_user?(user)
return true if self.email.blank? && self.domain.blank?
return true if self.email.present? && email_matches?(user.email)
self.domain.present? && domain_matches?(user.email)
end
def expired?
expires_at < Time.zone.now
end
@ -115,6 +144,8 @@ class Invite < ActiveRecord::Base
invite.destroy
invite = nil
end
email_digest = Digest::SHA256.hexdigest(email)
RateLimiter.new(invited_by, "reinvites-per-day-#{email_digest}", 3, 1.day.to_i).performed!
end
emailed_status = if opts[:skip_email] || invite&.emailed_status == emailed_status_types[:not_required]
@ -164,14 +195,11 @@ class Invite < ActiveRecord::Base
invite.reload
end
def redeem(email: nil, username: nil, name: nil, password: nil, user_custom_fields: nil, ip_address: nil, session: nil, email_token: nil)
def redeem(email: nil, username: nil, name: nil, password: nil, user_custom_fields: nil, ip_address: nil, session: nil, email_token: nil, redeeming_user: nil)
return if !redeemable?
if is_invite_link? && UserEmail.exists?(email: email)
raise UserExists.new I18n.t("invite_link.email_taken")
end
email = self.email if email.blank? && !is_invite_link?
InviteRedeemer.new(
invite: self,
email: email,
@ -181,10 +209,20 @@ class Invite < ActiveRecord::Base
user_custom_fields: user_custom_fields,
ip_address: ip_address,
session: session,
email_token: email_token
email_token: email_token,
redeeming_user: redeeming_user
).redeem
end
def self.redeem_for_existing_user(user)
invite = Invite.find_by(email: Email.downcase(user.email))
if invite.present? && invite.redeemable?
InviteRedeemer.new(invite: invite, redeeming_user: user).redeem
end
invite
end
# Deprecated: Replaced by redeem_for_existing_user in tests-passed
def self.redeem_from_email(email)
invite = Invite.find_by(email: Email.downcase(email))
InviteRedeemer.new(invite: invite, email: invite.email).redeem if invite

View File

@ -1,16 +1,50 @@
# frozen_string_literal: true
InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_custom_fields, :ip_address, :session, :email_token, keyword_init: true) do
# NOTE: There are a _lot_ of complicated rules and conditions for our
# invite system, and the code is spread out through a lot of places.
# Tread lightly and read carefully when modifying this code. You may
# also want to look at:
#
# * InvitesController
# * SessionController
# * Invite model
# * User model
#
# Invites that are scoped to a specific email (email IS NOT NULL on the Invite
# model) have different rules to invites that are considered an "invite link",
# (email IS NULL) on the Invite model.
InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_custom_fields, :ip_address, :session, :email_token, :redeeming_user, keyword_init: true) do
def redeem
ensure_email_is_present!(email)
Invite.transaction do
if invite_was_redeemed?
if can_redeem_invite? && mark_invite_redeemed
process_invitation
invited_user
end
end
end
# The email must be present in some form since many of the methods
# for processing + redemption rely on it. If it's still nil after
# these checks then we have hit an edge case and should not proceed!
def ensure_email_is_present!(email)
if email.blank?
Rails.logger.warn(
"email param was blank in InviteRedeemer for invite ID #{invite.id}. The `redeeming_user` was #{self.redeeming_user.present? ? "(ID: #{self.redeeming_user.id})" : "not"} present.",
)
end
if email.blank? && self.invite.is_email_invite?
self.email = self.invite.email
elsif self.redeeming_user.present?
self.email = self.redeeming_user.email
else
self.email = email
end
raise Discourse::InvalidParameters if self.email.blank?
end
# extracted from User cause it is very specific to invites
def self.create_user_from_invite(email:, invite:, username: nil, name: nil, password: nil, user_custom_fields: nil, ip_address: nil, session: nil, email_token: nil)
if username && UsernameValidator.new(username).valid_format? && User.username_available?(username, email)
@ -19,13 +53,6 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
available_username = UserNameSuggester.suggest(email)
end
if email.present? && invite.domain.present?
username, domain = email.split('@')
if domain.present? && invite.domain != domain
raise ActiveRecord::RecordNotSaved.new(I18n.t('invite.domain_not_allowed'))
end
end
user = User.where(staged: true).with_email(email.strip.downcase).first
user.unstage! if user
user ||= User.new
@ -40,10 +67,10 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
registration_ip_address: ip_address
}
if !SiteSetting.must_approve_users? ||
(SiteSetting.must_approve_users? && invite.invited_by.staff?) ||
EmailValidator.can_auto_approve_user?(user.email)
ReviewableUser.set_approved_fields!(user, invite.invited_by)
if (!SiteSetting.must_approve_users && SiteSetting.invite_only) ||
(SiteSetting.must_approve_users? && EmailValidator.can_auto_approve_user?(user.email))
ReviewableUser.set_approved_fields!(user, Discourse.system_user)
end
user_fields = UserField.all
@ -80,8 +107,10 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
user.save!
authenticator.finish
if invite.emailed_status != Invite.emailed_status_types[:not_required] && email == invite.email && invite.email_token.present? && email_token == invite.email_token
user.email_tokens.create!(email: user.email, scope: EmailToken.scopes[:signup])
if invite.emailed_status != Invite.emailed_status_types[:not_required] &&
email == invite.email &&
invite.email_token.present? &&
email_token == invite.email_token
user.activate
end
@ -90,33 +119,50 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
private
def invited_user
@invited_user ||= get_invited_user
def can_redeem_invite?
return false if !invite.redeemable?
return false if email.blank?
# Invite scoped to email has already been redeemed by anyone.
if invite.is_email_invite? && InvitedUser.exists?(invite_id: invite.id)
return false
end
# The email will be present for either an invite link (where the user provides
# us the email manually) or for an invite scoped to an email, where we
# prefill the email and do not let the user modify it.
#
# Note that an invite link can also have a domain scope which must be checked.
email_to_check = redeeming_user&.email || email
if invite.email.present? && !invite.email_matches?(email_to_check)
raise ActiveRecord::RecordNotSaved.new(I18n.t('invite.not_matching_email'))
end
if invite.domain.present? && !invite.domain_matches?(email_to_check)
raise ActiveRecord::RecordNotSaved.new(I18n.t('invite.domain_not_allowed'))
end
# Anon user is trying to redeem an invitation, if an existing user already
# redeemed it then we cannot redeem now.
redeeming_user ||= User.where(admin: false, staged: false).find_by_email(email)
if redeeming_user.present? && InvitedUser.exists?(user_id: redeeming_user.id, invite_id: invite.id)
return false
end
true
end
def process_invitation
approve_account_if_needed
add_to_private_topics_if_invited
add_user_to_groups
send_welcome_message
notify_invitee
end
def invite_was_redeemed?
mark_invite_redeemed
end
def mark_invite_redeemed
if !invite.is_invite_link? && InvitedUser.exists?(invite_id: invite.id)
return false
end
existing_user = get_existing_user
if existing_user.present? && InvitedUser.exists?(user_id: existing_user.id, invite_id: invite.id)
return false
end
@invited_user_record = InvitedUser.create!(invite_id: invite.id, redeemed_at: Time.zone.now)
if @invited_user_record.present?
Invite.increment_counter(:redemption_count, invite.id)
delete_duplicate_invites
@ -125,9 +171,20 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
@invited_user_record.present?
end
def get_invited_user
result = get_existing_user
result ||= InviteRedeemer.create_user_from_invite(
def invited_user
return @invited_user if defined?(@invited_user)
# The redeeming user is an already logged in user or a user who is
# activating their account who is redeeming the invite,
# which is valid for existing users to be invited to topics or groups.
if redeeming_user.present?
@invited_user = redeeming_user
return @invited_user
end
# If there was no logged in user then we must attempt to create
# one based on the provided params.
invited_user ||= InviteRedeemer.create_user_from_invite(
email: email,
invite: invite,
username: username,
@ -138,18 +195,24 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
session: session,
email_token: email_token
)
result.send_welcome_message = false
result
end
def get_existing_user
User.where(admin: false, staged: false).find_by_email(email)
invited_user.send_welcome_message = false
@invited_user = invited_user
@invited_user
end
def add_to_private_topics_if_invited
topic_ids = Topic.where(archetype: Archetype::private_message).includes(:invites).where(invites: { email: email }).pluck(:id)
# Should not happen because of ensure_email_is_present!, but better to cover bases.
return if email.blank?
topic_ids = TopicInvite.joins(:invite)
.joins(:topic)
.where("topics.archetype = ?", Archetype::private_message)
.where("invites.email = ?", email)
.pluck(:topic_id)
topic_ids.each do |id|
TopicAllowedUser.create!(user_id: invited_user.id, topic_id: id) unless TopicAllowedUser.exists?(user_id: invited_user.id, topic_id: id)
if !TopicAllowedUser.exists?(user_id: invited_user.id, topic_id: id)
TopicAllowedUser.create!(user_id: invited_user.id, topic_id: id)
end
end
end
@ -170,27 +233,18 @@ InviteRedeemer = Struct.new(:invite, :email, :username, :name, :password, :user_
invited_user.send_welcome_message = true
end
def approve_account_if_needed
if invited_user.present? && reviewable_user = ReviewableUser.find_by(target: invited_user, status: Reviewable.statuses[:pending])
reviewable_user.perform(
invite.invited_by,
:approve_user,
send_email: false,
approved_by_invite: true
)
end
end
def notify_invitee
if inviter = invite.invited_by
inviter.notifications.create!(
notification_type: Notification.types[:invitee_accepted],
data: { display_username: invited_user.username }.to_json
)
end
return if invite.invited_by.blank?
invite.invited_by.notifications.create!(
notification_type: Notification.types[:invitee_accepted],
data: { display_username: invited_user.username }.to_json
)
end
def delete_duplicate_invites
# Should not happen because of ensure_email_is_present!, but better to cover bases.
return if email.blank?
Invite
.where('invites.max_redemptions_allowed = 1')
.joins("LEFT JOIN invited_users ON invites.id = invited_users.invite_id")

View File

@ -15,7 +15,7 @@ class RemoteTheme < ActiveRecord::Base
ALLOWED_FIELDS = %w{scss embedded_scss head_tag header after_header body_tag footer}
GITHUB_REGEXP = /^https?:\/\/github\.com\//
GITHUB_SSH_REGEXP = /^git@github\.com:/
GITHUB_SSH_REGEXP = /^ssh:\/\/git@github\.com:/
has_one :theme, autosave: false
scope :joined_remotes, -> {
@ -25,8 +25,10 @@ class RemoteTheme < ActiveRecord::Base
validates_format_of :minimum_discourse_version, :maximum_discourse_version, with: Discourse::VERSION_REGEXP, allow_nil: true
def self.extract_theme_info(importer)
JSON.parse(importer["about.json"])
rescue TypeError, JSON::ParserError
json = JSON.parse(importer["about.json"])
json.fetch("name")
json
rescue TypeError, JSON::ParserError, KeyError
raise ImportError.new I18n.t("themes.import_error.about_json")
end
@ -80,6 +82,7 @@ class RemoteTheme < ActiveRecord::Base
importer.import!
theme_info = RemoteTheme.extract_theme_info(importer)
component = [true, "true"].include?(theme_info["component"])
theme = Theme.new(user_id: user&.id || -1, name: theme_info["name"], component: component)
theme.child_components = theme_info["components"].presence || []

View File

@ -1,6 +1,9 @@
# frozen_string_literal: true
class ReviewableFlaggedPost < Reviewable
scope :pending_and_default_visible, -> {
pending.default_visible
}
# Penalties are handled by the modal after the action is performed
def self.action_aliases

View File

@ -12,7 +12,7 @@ class ReviewableUser < Reviewable
def build_actions(actions, guardian, args)
return unless pending?
if guardian.can_approve?(target) || args[:approved_by_invite]
if guardian.can_approve?(target)
actions.add(:approve_user) do |a|
a.icon = 'user-plus'
a.label = "reviewables.actions.approve_user.title"

View File

@ -107,7 +107,7 @@ class Tag < ActiveRecord::Base
return [] if scope_category_ids.empty?
filter_sql = guardian&.is_staff? ? '' : " AND tags.id NOT IN (#{DiscourseTagging.hidden_tags_query.select(:id).to_sql})"
filter_sql = guardian&.is_staff? ? '' : " AND tags.id IN (#{DiscourseTagging.visible_tags(guardian).select(:id).to_sql})"
tag_names_with_counts = DB.query <<~SQL
SELECT tags.name as tag_name, SUM(stats.topic_count) AS sum_topic_count

View File

@ -115,7 +115,12 @@ class Theme < ActiveRecord::Base
end
def update_javascript_cache!
all_extra_js = theme_fields.where(target_id: Theme.targets[:extra_js]).pluck(:value_baked).join("\n")
all_extra_js = theme_fields
.where(target_id: Theme.targets[:extra_js])
.order(:name, :id)
.pluck(:value_baked)
.join("\n")
if all_extra_js.present?
js_compiler = ThemeJavascriptCompiler.new(id, name)
js_compiler.append_raw_script(all_extra_js)

View File

@ -424,8 +424,12 @@ class Topic < ActiveRecord::Base
posts.where(post_type: Post.types[:regular], user_deleted: false).order('score desc nulls last').limit(1).first
end
def self.has_flag_scope
ReviewableFlaggedPost.pending_and_default_visible
end
def has_flags?
ReviewableFlaggedPost.pending.default_visible.where(topic_id: id).exists?
self.class.has_flag_scope.exists?(topic_id: self.id)
end
def is_official_warning?

View File

@ -218,6 +218,7 @@ class User < ActiveRecord::Base
scope :suspended, -> { where('suspended_till IS NOT NULL AND suspended_till > ?', Time.zone.now) }
scope :not_suspended, -> { where('suspended_till IS NULL OR suspended_till <= ?', Time.zone.now) }
scope :activated, -> { where(active: true) }
scope :not_staged, -> { where(staged: false) }
scope :filter_by_username, ->(filter) do
if filter.is_a?(Array)

View File

@ -18,6 +18,10 @@ class UserEmail < ActiveRecord::Base
scope :secondary, -> { where(primary: false) }
before_save ->() { destroy_email_tokens(self.email_was) }, if: :will_save_change_to_email?
after_destroy { destroy_email_tokens(self.email) }
def normalize_email
self.normalized_email = if self.email.present?
username, domain = self.email.split('@', 2)
@ -62,6 +66,10 @@ class UserEmail < ActiveRecord::Base
)
end
end
def destroy_email_tokens(email)
EmailToken.where(email: email).destroy_all
end
end
# == Schema Information

View File

@ -8,7 +8,8 @@ class UserProfile < ActiveRecord::Base
belongs_to :featured_topic, class_name: 'Topic'
validates :bio_raw, length: { maximum: 3000 }
validates :website, url: true, allow_blank: true, if: Proc.new { |c| c.new_record? || c.website_changed? }
validates :website, url: true, length: { maximum: 3000 }, allow_blank: true, if: Proc.new { |c| c.new_record? || c.website_changed? }
validates :location, length: { maximum: 3000 }
validates :user, presence: true
before_save :cook
after_save :trigger_badges
@ -168,8 +169,8 @@ end
# Table name: user_profiles
#
# user_id :integer not null, primary key
# location :string
# website :string
# location :string(3000)
# website :string(3000)
# bio_raw :text
# bio_cooked :text
# dismissed_banner_key :integer

View File

@ -15,6 +15,7 @@ class WebHook < ActiveRecord::Base
validates_presence_of :content_type
validates_presence_of :last_delivery_status
validates_presence_of :web_hook_event_types, unless: :wildcard_web_hook?
validate :ensure_payload_url_allowed, if: :payload_url_changed?
before_save :strip_url
@ -113,6 +114,23 @@ class WebHook < ActiveRecord::Base
def self.guardian
Guardian.new(Discourse.system_user)
end
# This check is to improve UX
# IPs are re-checked at request time
def ensure_payload_url_allowed
return if payload_url.blank?
uri = URI(payload_url.strip)
allowed = begin
FinalDestination::SSRFDetector.lookup_and_filter_ips(uri.hostname).present?
rescue FinalDestination::SSRFDetector::DisallowedIpError
false
end
if !allowed
self.errors.add(:base, I18n.t("webhooks.payload_url.blocked_or_internal"))
end
end
end
# == Schema Information

View File

@ -33,19 +33,30 @@ class CategorySerializer < SiteCategorySerializer
def group_permissions
@group_permissions ||= begin
perms = object.category_groups.joins(:group).includes(:group).order("groups.name").map do |cg|
{
permission_type: cg.permission_type,
group_name: cg.group.name
}
end
perms = object
.category_groups
.joins(:group)
.includes(:group)
.merge(Group.visible_groups(scope&.user, "groups.name ASC", include_everyone: true))
.map do |cg|
{
permission_type: cg.permission_type,
group_name: cg.group.name
}
end
if perms.length == 0 && !object.read_restricted
perms << { permission_type: CategoryGroup.permission_types[:full], group_name: Group[:everyone]&.name.presence || :everyone }
end
perms
end
end
def include_group_permissions?
scope&.can_edit?(object)
end
def include_available_groups?
scope && scope.can_edit?(object)
end

View File

@ -0,0 +1,27 @@
# frozen_string_literal: true
# Post and topic attributes are only included when the `allowed_user_badge_topic_ids` option is provided. The caller of the
# serializer is responsible for ensuring that the topic ids in the options can be seen by the scope of the user by passing
# the result of `Guardian#can_see_topic_ids` to the `allowed_user_badge_topic_ids` option.
module UserBadgePostAndTopicAttributesMixin
private
def include_post_attributes?
return false if !object.badge.show_posts || !object.post
return true if scope.is_admin?
allowed_user_badge_topic_ids = options[:allowed_user_badge_topic_ids]
return false if allowed_user_badge_topic_ids.blank?
topic_id = object.post.topic_id
return false if topic_id.blank?
allowed_user_badge_topic_ids.include?(topic_id)
end
def include_topic_attributes?
include_post_attributes? && object.post.topic
end
end

View File

@ -1,27 +1,34 @@
# frozen_string_literal: true
class DetailedUserBadgeSerializer < BasicUserBadgeSerializer
include UserBadgePostAndTopicAttributesMixin
has_one :granted_by, serializer: UserBadgeSerializer::UserSerializer
attributes :post_number, :topic_id, :topic_title, :is_favorite, :can_favorite
def include_post_number?
object.post
def post_number
object.post.post_number
end
alias :include_topic_id? :include_post_number?
alias :include_topic_title? :include_post_number?
def post_number
object.post.post_number if object.post
def include_post_number?
include_post_attributes?
end
def topic_id
object.post.topic_id if object.post
object.post.topic_id
end
def include_topic_id?
include_topic_attributes?
end
def topic_title
object.post.topic.title if object.post && object.post.topic
object.post.topic.title
end
def include_topic_title?
include_topic_id?
end
def can_favorite

View File

@ -1,6 +1,7 @@
# frozen_string_literal: true
class UserBadgeSerializer < ApplicationSerializer
include UserBadgePostAndTopicAttributesMixin
class UserSerializer < BasicUserSerializer
include UserPrimaryGroupMixin
@ -22,10 +23,9 @@ class UserBadgeSerializer < ApplicationSerializer
end
def include_post_id?
object.badge.show_posts && object.post_id && object.post
include_post_attributes?
end
alias :include_topic? :include_post_id?
alias :include_post_number? :include_post_id?
def post_number
@ -35,4 +35,8 @@ class UserBadgeSerializer < ApplicationSerializer
def topic
object.post.topic
end
def include_topic?
include_topic_attributes?
end
end

View File

@ -0,0 +1,57 @@
# frozen_string_literal: true
class WebHookEmitter
REQUEST_TIMEOUT = 20
def initialize(webhook, webhook_event)
@webhook = webhook
@webhook_event = webhook_event
end
def emit!(headers:, body:)
uri = URI(@webhook.payload_url.strip)
connection_opts = {
request: {
write_timeout: REQUEST_TIMEOUT,
read_timeout: REQUEST_TIMEOUT,
open_timeout: REQUEST_TIMEOUT
},
}
if !@webhook.verify_certificate
connection_opts[:ssl] = { verify: false }
end
conn = Faraday.new(nil, connection_opts) do |f|
f.adapter FinalDestination::FaradayAdapter
end
start = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond)
error = nil
response = nil
begin
response = conn.post(uri.to_s, body, headers)
rescue => e
error = e
end
duration = Process.clock_gettime(Process::CLOCK_MONOTONIC, :millisecond) - start
event_update_args = {
headers: MultiJson.dump(headers),
duration: duration,
}
if response
event_update_args[:response_headers] = MultiJson.dump(response.headers)
event_update_args[:response_body] = response.body
event_update_args[:status] = response.status
else
event_update_args[:status] = -1
if error.is_a?(Faraday::Error) && error.wrapped_exception.is_a?(FinalDestination::SSRFDetector::DisallowedIpError)
error = I18n.t("webhooks.payload_url.blocked_or_internal")
end
event_update_args[:response_headers] = MultiJson.dump(error: error)
end
@webhook_event.update!(**event_update_args)
response
end
end

View File

@ -246,6 +246,8 @@ module Discourse
# see: http://stackoverflow.com/questions/11894180/how-does-one-correctly-add-custom-sql-dml-in-migrations/11894420#11894420
config.active_record.schema_format = :sql
config.active_record.yaml_column_permitted_classes = [Hash, HashWithIndifferentAccess, Time, Symbol]
# We use this in development-mode only (see development.rb)
config.active_record.use_schema_cache_dump = false

View File

View File

@ -3597,7 +3597,6 @@ ar:
default_list_filter: "تصفية القائمة الافتراضية:"
allow_badges_label: "السماح بمنح الشارات في هذه الفئة"
edit_permissions: "تعديل الأذونات"
reviewable_by_group: "بالإضافة إلى فريق العمل، يمكن أيضًا مراجعة المحتوى في هذه الفئة بواسطة:"
review_group_name: "اسم المجموعة"
require_topic_approval: "طلب موافقة المشرف على جميع الموضوعات الجديدة"
require_reply_approval: "طلب موافقة المشرف على جميع الردود الجديدة"

View File

@ -2951,7 +2951,6 @@ da:
default_list_filter: "Standard Listefilter:"
allow_badges_label: "Tillad at emblemer bliver tildelt i denne kategori"
edit_permissions: "Redigér tilladelser"
reviewable_by_group: "Ud over personalet kan indholdet i denne kategori også gennemgås af:"
review_group_name: "gruppe navn"
require_topic_approval: "Kræv moderator godkendelse af alle nye emner"
require_reply_approval: "Kræv moderator godkendelse af alle nye svar"

View File

@ -2590,7 +2590,6 @@ el:
default_list_filter: "Προεπιλεγμένο φίλτρο λίστας:"
allow_badges_label: "Να επιτρέπεται η απονομή παράσημων σε αυτή την κατηγορία"
edit_permissions: "Επεξεργασία Δικαιωμάτων"
reviewable_by_group: "Εκτός από το προσωπικό, το περιεχόμενο αυτής της κατηγορίας μπορεί επίσης να αναθεωρηθεί από:"
review_group_name: "όνομα ομάδας"
require_topic_approval: "Απαιτήστε έγκριση συντονιστή για όλα τα νέα θέματα"
require_reply_approval: "Απαιτήστε έγκριση συντονιστή για όλες τις νέες απαντήσεις"

View File

@ -1988,6 +1988,7 @@ en:
name_label: "Name"
password_label: "Password"
optional_description: "(optional)"
existing_user_can_redeem: "Redeem your invitation to a topic or group."
password_reset:
continue: "Continue to %{site_name}"
@ -4245,7 +4246,6 @@ en:
go_back: "Back to list"
payload_url: "Payload URL"
payload_url_placeholder: "https://example.com/postreceive"
warn_local_payload_url: "It seems you are trying to set up the webhook to a local url. Event delivered to a local address may cause side-effect or unexpected behaviors. Continue?"
secret_invalid: "Secret must not have any blank characters."
secret_too_short: "Secret should be at least 12 characters."
secret_placeholder: "An optional string, used for generating signature"
@ -4534,7 +4534,6 @@ en:
is_private: "Theme is in a private git repository"
remote_branch: "Branch name (optional)"
public_key: "Grant the following public key access to the repo:"
public_key_note: "After entering a valid private repository URL above, an SSH key will be generated and displayed here."
install: "Install"
installed: "Installed"
install_popular: "Popular"

View File

@ -173,6 +173,7 @@ es:
themes:
default_description: "Por defecto"
broken_theme_alert: "Tu sitio puede que no funcione porque el tema / componente %{theme} tiene errores. Desactívalo en %{path}."
broken_decorator_alert: "Puede que las publicaciones no se muestren correctamente porque uno de los decoradores de contenido de publicaciones de tu sitio está causando errores. Revisa la consola de desarrollo del navegador para más información."
s3:
regions:
ap_northeast_1: "Asia-Pacífico (Tokio)"
@ -3071,7 +3072,7 @@ es:
default_list_filter: "Filtro de lista por defecto:"
allow_badges_label: "Permitir que se concedan insignias en esta categoría"
edit_permissions: "Editar permisos"
reviewable_by_group: "Además del personal, el contenido de esta categoría también puede ser revisado por:"
reviewable_by_group: "Además del personal, los siguientes grupos también pueden revisar el contenido de esta categoría:"
review_group_name: "nombre del grupo"
require_topic_approval: "Requiere aprobación del moderador para todos los temas nuevos"
require_reply_approval: "Requiere aprobación del moderador para todas las respuestas nuevas"

View File

@ -2161,7 +2161,6 @@ et:
default_list_filter: "Vaikimisi teemade filter:"
allow_badges_label: "Luba selles foorumis autasustamist märgistega"
edit_permissions: "Muuda kasutusõigusi"
reviewable_by_group: "Lisaks meeskonnaliikmetle saavad selle kategooria sisu üle vaadata ka:"
review_group_name: "grupi nimi"
require_topic_approval: "Nõua moderaatori heakskiitu kõikidele uutele teemadele"
require_reply_approval: "Nõua moderaatori heakskiitu kõikidele uutele vastustele"

View File

@ -2956,7 +2956,6 @@ fi:
default_list_filter: "Oletusluettelosuodatin:"
allow_badges_label: "Salli kunniamerkkien myöntäminen tällä alueella"
edit_permissions: "Muokkaa oikeuksia"
reviewable_by_group: "Henkilökunnan lisäksi tämän alueen sisältöä voi käsitellä myös:"
review_group_name: "ryhmän nimi"
require_topic_approval: "Edellytä valvojan hyväksyntää kaikille uusille ketjuille"
require_reply_approval: "Edellytä valvojan hyväksyntää kaikille uusille vastauksille"

View File

@ -2953,7 +2953,6 @@ fr:
default_list_filter: "Filtre de liste par défaut :"
allow_badges_label: "Autoriser les badges à être accordés dans cette catégorie"
edit_permissions: "Modifier les permissions"
reviewable_by_group: "En plus des responsables, le contenu de cette catégorie peut également être examiné par :"
review_group_name: "nom du groupe"
require_topic_approval: "Nécessiter l'approbation pour chaque nouveau sujet"
require_reply_approval: "Nécessiter l'approbation pour chaque nouvelle réponse"

View File

@ -2859,7 +2859,6 @@ gl:
default_list_filter: "Filtro de listaxe predeterminado:"
allow_badges_label: "Permitir adxudicar insignias nesta categoría"
edit_permissions: "Editar permisos"
reviewable_by_group: "Ademais do equipo, o contido desta categoría tamén pode ser revisado por:"
review_group_name: "nome do grupo"
require_topic_approval: "Require a aprobación de todos os temas novos polo moderador"
require_reply_approval: "Require a aprobación de todas as respostas novas polo moderador"

View File

@ -2834,6 +2834,7 @@ hu:
default_view: "Alapértelmezett témakörök"
allow_badges_label: "Kitűzök elnyerésének engedélyezése ebben a kategóriában"
edit_permissions: "Jogok szerkesztése"
reviewable_by_group: "Az ebbe a kategóriába tartozó tartalmakat a stábon kívül a következők is jóváhagyhatják:"
review_group_name: "csoport neve"
this_year: "ez az év"
position: "Kategóriák oldalon elfoglalt pozíció:"

View File

@ -3026,7 +3026,7 @@ it:
default_list_filter: "Filtro predefinito della lista:"
allow_badges_label: "Permetti l'assegnazione di distintivi in questa categoria"
edit_permissions: "Modifica Permessi"
reviewable_by_group: "Oltre allo staff, i contenuti di questa categoria possono essere esaminati da:"
reviewable_by_group: "Oltre che dal personale, i contenuti di questa categoria possono essere revisionati anche da:"
review_group_name: "nome gruppo"
require_topic_approval: "Richiedi l'approvazione di un moderatore per tutti i nuovi argomenti"
require_reply_approval: "Richiedi l'approvazione di un moderatore per tutte le nuove risposte"

View File

@ -2886,7 +2886,6 @@ ja:
default_list_filter: "デフォルトのリストのフィルタ:"
allow_badges_label: "このカテゴリでバッジの付与を許可する"
edit_permissions: "権限を編集"
reviewable_by_group: "このカテゴリのコンテンツはスタッフのほか、次のユーザーもレビューできる:"
review_group_name: "グループ名"
require_topic_approval: "すべての新しいトピックにモデレーターの承認を必要とする"
require_reply_approval: "すべての新しい返信にモデレーターの承認を必要とする"

View File

@ -2918,7 +2918,6 @@ ko:
default_list_filter: "목록 기본 필터:"
allow_badges_label: "배지가 이 카테고리에서 주어질 수 있도록 허용"
edit_permissions: "권한 수정"
reviewable_by_group: "이 카테고리의 콘텐츠는 관리자 외에도 다음과 같은 방법으로 검토할 수 있습니다."
review_group_name: "그룹명"
require_topic_approval: "모든 새 글에 대한 관리자 승인 필요"
require_reply_approval: "모든 새 댓글의 관리자 승인 필요"

View File

@ -2898,7 +2898,6 @@ lt:
default_list_filter: "Numatytasis sąrašo filtras:"
allow_badges_label: "Leisti trofėjų apdovanojimus šioje kategorijoje"
edit_permissions: "Redaguoti leidimus"
reviewable_by_group: "Be darbuotojų, šios kategorijos turinį taip pat gali peržiūrėti:"
review_group_name: "grupės pavadinimas"
require_topic_approval: "Reikalauti, kad moderatorius patvirtintų visas naujas temas"
require_reply_approval: "Reikalauti, kad moderatorius patvirtintų visus naujus atsakymus"

View File

@ -2910,7 +2910,6 @@ nb_NO:
default_list_filter: "Standard listefilter:"
allow_badges_label: "Tillat merker å bli tildelt i denne kategorien"
edit_permissions: "Rediger tillatelser"
reviewable_by_group: "I tillegg til de ansatte, kan innholdet i denne kategorien også gjennomgås ved å:"
review_group_name: "gruppenavn"
require_topic_approval: "Krev godkjennelse fra moderator for alle nye emner"
require_reply_approval: "Krev godkjennelse fra moderator for alle nye svar"

View File

@ -2970,7 +2970,6 @@ nl:
default_list_filter: "Standaard lijstfilter:"
allow_badges_label: "Badges laten toekennen in deze categorie"
edit_permissions: "Toestemmingen bewerken"
reviewable_by_group: "Naast stafleden kan inhoud in deze categorie ook worden beoordeeld door:"
review_group_name: "groepsnaam"
require_topic_approval: "Goedkeuring van moderator voor alle nieuwe topics vereisen"
require_reply_approval: "Goedkeuring van moderator voor alle nieuwe antwoorden vereisen"

Some files were not shown because too many files have changed in this diff Show More