diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/bug_report.md
similarity index 83%
rename from .github/ISSUE_TEMPLATE.md
rename to .github/ISSUE_TEMPLATE/bug_report.md
index 3a375bcbe9..9c0577106e 100644
--- a/.github/ISSUE_TEMPLATE.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,10 +1,19 @@
+---
+name: Bug report
+about: Report a bug
+title: ''
+labels: type:bug
+assignees: ''
+
+---
+
diff --git a/README.md b/README.md
index 4895254926..33e7a8956b 100644
--- a/README.md
+++ b/README.md
@@ -14,39 +14,52 @@
License
-
+
- Figure 1: A screenshot of a project being edited in Overleaf Community Edition.
+ Figure 1: A screenshot of a project being edited in Overleaf Extended Community Edition.
## Community Edition
-[Overleaf](https://www.overleaf.com) is an open-source online real-time collaborative LaTeX editor. We run a hosted version at [www.overleaf.com](https://www.overleaf.com), but you can also run your own local version, and contribute to the development of Overleaf.
+[Overleaf](https://www.overleaf.com) is an open-source online real-time collaborative LaTeX editor. Overleaf runs a hosted version at [www.overleaf.com](https://www.overleaf.com), but you can also run your own local version, and contribute to the development of Overleaf.
+
+## Extended Community Edition
+
+The present "extended" version of Overleaf CE includes:
+
+- Template Gallery
+- Sandboxed Compiles with TeX Live image selection
+- LDAP authentication
+- SAML authentication
+- OpenID Connect authentication
+- Real-time track changes and comments
+- Autocomplete of reference keys
+- Symbol Palette
+- "From External URL" feature
+
+> [!CAUTION]
+> Overleaf Community Edition is intended for use in environments where **all** users are trusted. Community Edition is **not** appropriate for scenarios where isolation of users is required due to Sandbox Compiles not being available. When not using Sandboxed Compiles, users have full read and write access to the `sharelatex` container resources (filesystem, network, environment variables) when running LaTeX compiles.
+Therefore, in any environment where not all users can be fully trusted, it is strongly recommended to enable the Sandboxed Compiles feature available in the Extended Community Edition.
+
+For more information on Sandbox Compiles check out Overleaf [documentation](https://docs.overleaf.com/on-premises/configuration/overleaf-toolkit/server-pro-only-configuration/sandboxed-compiles).
## Enterprise
-If you want help installing and maintaining Overleaf in your lab or workplace, we offer an officially supported version called [Overleaf Server Pro](https://www.overleaf.com/for/enterprises). It also includes more features for security (SSO with LDAP or SAML), administration and collaboration (e.g. tracked changes). [Find out more!](https://www.overleaf.com/for/enterprises)
-
-## Keeping up to date
-
-Sign up to the [mailing list](https://mailchi.mp/overleaf.com/community-edition-and-server-pro) to get updates on Overleaf releases and development.
+If you want help installing and maintaining Overleaf in your lab or workplace, Overleaf offers an officially supported version called [Overleaf Server Pro](https://www.overleaf.com/for/enterprises).
## Installation
-We have detailed installation instructions in the [Overleaf Toolkit](https://github.com/overleaf/toolkit/).
-
-## Upgrading
-
-If you are upgrading from a previous version of Overleaf, please see the [Release Notes section on the Wiki](https://github.com/overleaf/overleaf/wiki#release-notes) for all of the versions between your current version and the version you are upgrading to.
+Detailed installation instructions can be found in the [Overleaf Toolkit](https://github.com/overleaf/toolkit/).
+Configuration details and release history for the Extended Community Edition can be found on the [Extended CE Wiki Page](https://github.com/yu-i-i/overleaf-cep/wiki).
## Overleaf Docker Image
This repo contains two dockerfiles, [`Dockerfile-base`](server-ce/Dockerfile-base), which builds the
-`sharelatex/sharelatex-base` image, and [`Dockerfile`](server-ce/Dockerfile) which builds the
-`sharelatex/sharelatex` (or "community") image.
+`sharelatex/sharelatex-base:ext-ce` image, and [`Dockerfile`](server-ce/Dockerfile) which builds the
+`sharelatex/sharelatex:ext-ce` image.
The Base image generally contains the basic dependencies like `wget`, plus `texlive`.
-We split this out because it's a pretty heavy set of
+This is split out because it's a pretty heavy set of
dependencies, and it's nice to not have to rebuild all of that every time.
The `sharelatex/sharelatex` image extends the base image and adds the actual Overleaf code
@@ -54,20 +67,16 @@ and services.
Use `make build-base` and `make build-community` from `server-ce/` to build these images.
-We use the [Phusion base-image](https://github.com/phusion/baseimage-docker)
-(which is extended by our `base` image) to provide us with a VM-like container
+The [Phusion base-image](https://github.com/phusion/baseimage-docker)
+(which is extended by the `base` image) provides a VM-like container
in which to run the Overleaf services. Baseimage uses the `runit` service
-manager to manage services, and we add our init-scripts from the `server-ce/runit`
-folder.
-
-
-## Contributing
-
-Please see the [CONTRIBUTING](CONTRIBUTING.md) file for information on contributing to the development of Overleaf.
+manager to manage services, and init scripts from the `server-ce/runit`
+folder are added.
## Authors
-[The Overleaf Team](https://www.overleaf.com/about)
+[The Overleaf Team](https://www.overleaf.com/about)
+[yu-i-i](https://github.com/yu-i-i/overleaf-cep) — Extensions for CE unless otherwise noted
## License
diff --git a/develop/README.md b/develop/README.md
index 568259c4e3..8e3f89862c 100644
--- a/develop/README.md
+++ b/develop/README.md
@@ -42,7 +42,7 @@ To do this, use the included `bin/dev` script:
bin/dev
```
-This will start all services using `nodemon`, which will automatically monitor the code and restart the services as necessary.
+This will start all services using `node --watch`, which will automatically monitor the code and restart the services as necessary.
To improve performance, you can start only a subset of the services in development mode by providing a space-separated list to the `bin/dev` script:
@@ -77,6 +77,7 @@ each service:
| `filestore` | 9235 |
| `notifications` | 9236 |
| `real-time` | 9237 |
+| `references` | 9238 |
| `history-v1` | 9239 |
| `project-history` | 9240 |
diff --git a/develop/dev.env b/develop/dev.env
index aae91497db..b003e4e0eb 100644
--- a/develop/dev.env
+++ b/develop/dev.env
@@ -6,14 +6,18 @@ DOCUMENT_UPDATER_HOST=document-updater
FILESTORE_HOST=filestore
GRACEFUL_SHUTDOWN_DELAY_SECONDS=0
HISTORY_V1_HOST=history-v1
+HISTORY_REDIS_HOST=redis
LISTEN_ADDRESS=0.0.0.0
MONGO_HOST=mongo
MONGO_URL=mongodb://mongo/sharelatex?directConnection=true
NOTIFICATIONS_HOST=notifications
PROJECT_HISTORY_HOST=project-history
+QUEUES_REDIS_HOST=redis
REALTIME_HOST=real-time
REDIS_HOST=redis
+REFERENCES_HOST=references
SESSION_SECRET=foo
+V1_HISTORY_HOST=history-v1
WEBPACK_HOST=webpack
WEB_API_PASSWORD=overleaf
WEB_API_USER=overleaf
diff --git a/develop/docker-compose.dev.yml b/develop/docker-compose.dev.yml
index 4432a24162..65e15ef07b 100644
--- a/develop/docker-compose.dev.yml
+++ b/develop/docker-compose.dev.yml
@@ -112,8 +112,19 @@ services:
- ../services/real-time/app.js:/overleaf/services/real-time/app.js
- ../services/real-time/config:/overleaf/services/real-time/config
+ references:
+ command: ["node", "--watch", "app.js"]
+ environment:
+ - NODE_OPTIONS=--inspect=0.0.0.0:9229
+ ports:
+ - "127.0.0.1:9238:9229"
+ volumes:
+ - ../services/references/app:/overleaf/services/references/app
+ - ../services/references/config:/overleaf/services/references/config
+ - ../services/references/app.js:/overleaf/services/references/app.js
+
web:
- command: ["node", "--watch", "app.js", "--watch-locales"]
+ command: ["node", "--watch", "app.mjs", "--watch-locales"]
environment:
- NODE_OPTIONS=--inspect=0.0.0.0:9229
ports:
diff --git a/develop/docker-compose.yml b/develop/docker-compose.yml
index 750e11ac87..e5b84c38b3 100644
--- a/develop/docker-compose.yml
+++ b/develop/docker-compose.yml
@@ -25,10 +25,10 @@ services:
env_file:
- dev.env
environment:
- - DOCKER_RUNNER=true
- TEXLIVE_IMAGE=texlive-full # docker build texlive -t texlive-full
- - COMPILES_HOST_DIR=${PWD}/compiles
- - OUTPUT_HOST_DIR=${PWD}/output
+ - SANDBOXED_COMPILES=true
+ - SANDBOXED_COMPILES_HOST_DIR_COMPILES=${PWD}/compiles
+ - SANDBOXED_COMPILES_HOST_DIR_OUTPUT=${PWD}/output
user: root
volumes:
- ${PWD}/compiles:/overleaf/services/clsi/compiles
@@ -123,7 +123,7 @@ services:
dockerfile: services/real-time/Dockerfile
env_file:
- dev.env
-
+
redis:
image: redis:5
ports:
@@ -131,6 +131,13 @@ services:
volumes:
- redis-data:/data
+ references:
+ build:
+ context: ..
+ dockerfile: services/references/Dockerfile
+ env_file:
+ - dev.env
+
web:
build:
context: ..
@@ -140,7 +147,7 @@ services:
- dev.env
environment:
- APP_NAME=Overleaf Community Edition
- - ENABLED_LINKED_FILE_TYPES=project_file,project_output_file
+ - ENABLED_LINKED_FILE_TYPES=project_file,project_output_file,url
- EMAIL_CONFIRMATION_DISABLED=true
- NODE_ENV=development
- OVERLEAF_ALLOW_PUBLIC_ACCESS=true
@@ -161,6 +168,7 @@ services:
- notifications
- project-history
- real-time
+ - references
webpack:
build:
diff --git a/doc/logo.png b/doc/logo.png
index 106926b095..f154ac0cca 100644
Binary files a/doc/logo.png and b/doc/logo.png differ
diff --git a/doc/screenshot.png b/doc/screenshot.png
index 1c1f339630..92633192a5 100644
Binary files a/doc/screenshot.png and b/doc/screenshot.png differ
diff --git a/docker-compose.yml b/docker-compose.yml
index e257716789..962adfb5d8 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -32,7 +32,7 @@ services:
OVERLEAF_REDIS_HOST: redis
REDIS_HOST: redis
- ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file'
+ ENABLED_LINKED_FILE_TYPES: 'project_file,project_output_file,url'
# Enables Thumbnail generation using ImageMagick
ENABLE_CONVERSIONS: 'true'
diff --git a/libraries/access-token-encryptor/.nvmrc b/libraries/access-token-encryptor/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/access-token-encryptor/.nvmrc
+++ b/libraries/access-token-encryptor/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/access-token-encryptor/buildscript.txt b/libraries/access-token-encryptor/buildscript.txt
index 74c3bbbd24..8f08720e7e 100644
--- a/libraries/access-token-encryptor/buildscript.txt
+++ b/libraries/access-token-encryptor/buildscript.txt
@@ -1,10 +1,10 @@
access-token-encryptor
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/fetch-utils/.nvmrc b/libraries/fetch-utils/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/fetch-utils/.nvmrc
+++ b/libraries/fetch-utils/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/fetch-utils/buildscript.txt b/libraries/fetch-utils/buildscript.txt
index 91548ff7c6..7008a533a6 100644
--- a/libraries/fetch-utils/buildscript.txt
+++ b/libraries/fetch-utils/buildscript.txt
@@ -1,10 +1,10 @@
fetch-utils
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/logger/.nvmrc b/libraries/logger/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/logger/.nvmrc
+++ b/libraries/logger/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/logger/buildscript.txt b/libraries/logger/buildscript.txt
index 9008707b0e..e2520c4800 100644
--- a/libraries/logger/buildscript.txt
+++ b/libraries/logger/buildscript.txt
@@ -1,10 +1,10 @@
logger
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/metrics/.nvmrc b/libraries/metrics/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/metrics/.nvmrc
+++ b/libraries/metrics/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/metrics/buildscript.txt b/libraries/metrics/buildscript.txt
index 2c2e5d7531..d1e272c356 100644
--- a/libraries/metrics/buildscript.txt
+++ b/libraries/metrics/buildscript.txt
@@ -1,10 +1,10 @@
metrics
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/mongo-utils/.nvmrc b/libraries/mongo-utils/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/mongo-utils/.nvmrc
+++ b/libraries/mongo-utils/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/mongo-utils/buildscript.txt b/libraries/mongo-utils/buildscript.txt
index bda8d4f734..ff07040970 100644
--- a/libraries/mongo-utils/buildscript.txt
+++ b/libraries/mongo-utils/buildscript.txt
@@ -1,10 +1,10 @@
mongo-utils
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/o-error/.nvmrc b/libraries/o-error/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/o-error/.nvmrc
+++ b/libraries/o-error/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/o-error/buildscript.txt b/libraries/o-error/buildscript.txt
index a4134b4b60..6a9334411a 100644
--- a/libraries/o-error/buildscript.txt
+++ b/libraries/o-error/buildscript.txt
@@ -1,10 +1,10 @@
o-error
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/object-persistor/.nvmrc b/libraries/object-persistor/.nvmrc
index 8320a6d299..fc37597bcc 100644
--- a/libraries/object-persistor/.nvmrc
+++ b/libraries/object-persistor/.nvmrc
@@ -1 +1 @@
-22.15.1
+22.17.0
diff --git a/libraries/object-persistor/buildscript.txt b/libraries/object-persistor/buildscript.txt
index 75d2e09382..897e789700 100644
--- a/libraries/object-persistor/buildscript.txt
+++ b/libraries/object-persistor/buildscript.txt
@@ -1,10 +1,10 @@
object-persistor
--dependencies=None
---docker-repos=gcr.io/overleaf-ops
+--docker-repos=us-east1-docker.pkg.dev/overleaf-ops/ol-docker
--env-add=
--env-pass-through=
--esmock-loader=False
--is-library=True
---node-version=22.15.1
+--node-version=22.17.0
--public-repo=False
--script-version=4.7.0
diff --git a/libraries/object-persistor/src/PerProjectEncryptedS3Persistor.js b/libraries/object-persistor/src/PerProjectEncryptedS3Persistor.js
index 7bd4bb93e5..a0230128fe 100644
--- a/libraries/object-persistor/src/PerProjectEncryptedS3Persistor.js
+++ b/libraries/object-persistor/src/PerProjectEncryptedS3Persistor.js
@@ -33,6 +33,10 @@ const AES256_KEY_LENGTH = 32
* @property {() => Promise>} getRootKeyEncryptionKeys
*/
+/**
+ * @typedef {import('./types').ListDirectoryResult} ListDirectoryResult
+ */
+
/**
* Helper function to make TS happy when accessing error properties
* AWSError is not an actual class, so we cannot use instanceof.
@@ -391,9 +395,9 @@ class PerProjectEncryptedS3Persistor extends S3Persistor {
* A general "cache" for project keys is another alternative. For now, use a helper class.
*/
class CachedPerProjectEncryptedS3Persistor {
- /** @type SSECOptions */
+ /** @type SSECOptions */
#projectKeyOptions
- /** @type PerProjectEncryptedS3Persistor */
+ /** @type PerProjectEncryptedS3Persistor */
#parent
/**
@@ -424,6 +428,16 @@ class CachedPerProjectEncryptedS3Persistor {
return await this.#parent.getObjectSize(bucketName, path)
}
+ /**
+ *
+ * @param {string} bucketName
+ * @param {string} path
+ * @return {Promise}
+ */
+ async listDirectory(bucketName, path) {
+ return await this.#parent.listDirectory(bucketName, path)
+ }
+
/**
* @param {string} bucketName
* @param {string} path
diff --git a/libraries/object-persistor/src/S3Persistor.js b/libraries/object-persistor/src/S3Persistor.js
index 2835a271ff..1849838ba4 100644
--- a/libraries/object-persistor/src/S3Persistor.js
+++ b/libraries/object-persistor/src/S3Persistor.js
@@ -20,6 +20,18 @@ const { URL } = require('node:url')
const { WriteError, ReadError, NotFoundError } = require('./Errors')
const zlib = require('node:zlib')
+/**
+ * @typedef {import('aws-sdk/clients/s3').ListObjectsV2Output} ListObjectsV2Output
+ */
+
+/**
+ * @typedef {import('aws-sdk/clients/s3').Object} S3Object
+ */
+
+/**
+ * @typedef {import('./types').ListDirectoryResult} ListDirectoryResult
+ */
+
/**
* Wrapper with private fields to avoid revealing them on console, JSON.stringify or similar.
*/
@@ -266,26 +278,12 @@ class S3Persistor extends AbstractPersistor {
* @return {Promise}
*/
async deleteDirectory(bucketName, key, continuationToken) {
- let response
- const options = { Bucket: bucketName, Prefix: key }
- if (continuationToken) {
- options.ContinuationToken = continuationToken
- }
-
- try {
- response = await this._getClientForBucket(bucketName)
- .listObjectsV2(options)
- .promise()
- } catch (err) {
- throw PersistorHelper.wrapError(
- err,
- 'failed to list objects in S3',
- { bucketName, key },
- ReadError
- )
- }
-
- const objects = response.Contents?.map(item => ({ Key: item.Key || '' }))
+ const { contents, response } = await this.listDirectory(
+ bucketName,
+ key,
+ continuationToken
+ )
+ const objects = contents.map(item => ({ Key: item.Key || '' }))
if (objects?.length) {
try {
await this._getClientForBucket(bucketName)
@@ -316,6 +314,36 @@ class S3Persistor extends AbstractPersistor {
}
}
+ /**
+ *
+ * @param {string} bucketName
+ * @param {string} key
+ * @param {string} [continuationToken]
+ * @return {Promise}
+ */
+ async listDirectory(bucketName, key, continuationToken) {
+ let response
+ const options = { Bucket: bucketName, Prefix: key }
+ if (continuationToken) {
+ options.ContinuationToken = continuationToken
+ }
+
+ try {
+ response = await this._getClientForBucket(bucketName)
+ .listObjectsV2(options)
+ .promise()
+ } catch (err) {
+ throw PersistorHelper.wrapError(
+ err,
+ 'failed to list objects in S3',
+ { bucketName, key },
+ ReadError
+ )
+ }
+
+ return { contents: response.Contents ?? [], response }
+ }
+
/**
* @param {string} bucketName
* @param {string} key
diff --git a/libraries/object-persistor/src/types.d.ts b/libraries/object-persistor/src/types.d.ts
new file mode 100644
index 0000000000..5640685a5f
--- /dev/null
+++ b/libraries/object-persistor/src/types.d.ts
@@ -0,0 +1,6 @@
+import type { ListObjectsV2Output, Object } from 'aws-sdk/clients/s3'
+
+export type ListDirectoryResult = {
+ contents: Array