TestConfig.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. const fs = require('node:fs')
  2. const Path = require('node:path')
  3. const crypto = require('node:crypto')
  4. const {
  5. RootKeyEncryptionKey,
  6. } = require('@overleaf/object-persistor/src/PerProjectEncryptedS3Persistor')
  7. const AWS_S3_USER_FILES_STORAGE_CLASS =
  8. process.env.AWS_S3_USER_FILES_STORAGE_CLASS
  9. // use functions to get a fresh copy, not a reference, each time
  10. function s3BaseConfig() {
  11. return {
  12. endpoint: process.env.AWS_S3_ENDPOINT,
  13. pathStyle: true,
  14. partSize: 100 * 1024 * 1024,
  15. ca: [fs.readFileSync('/certs/public.crt')],
  16. }
  17. }
  18. function s3Config() {
  19. return {
  20. key: process.env.AWS_ACCESS_KEY_ID,
  21. secret: process.env.AWS_SECRET_ACCESS_KEY,
  22. ...s3BaseConfig(),
  23. }
  24. }
  25. const S3SSECKeys = [
  26. new RootKeyEncryptionKey(
  27. crypto.generateKeySync('aes', { length: 256 }).export(),
  28. Buffer.alloc(32)
  29. ),
  30. ]
  31. function s3SSECConfig() {
  32. return {
  33. ...s3Config(),
  34. ignoreErrorsFromDEKReEncryption: false,
  35. automaticallyRotateDEKEncryption: true,
  36. dataEncryptionKeyBucketName: process.env.AWS_S3_USER_FILES_DEK_BUCKET_NAME,
  37. pathToProjectFolder(_bucketName, path) {
  38. const match = path.match(/^[a-f0-9]{24}\//)
  39. if (!match) throw new Error('not a project-folder')
  40. const [projectFolder] = match
  41. return projectFolder
  42. },
  43. async getRootKeyEncryptionKeys() {
  44. return S3SSECKeys
  45. },
  46. storageClass: {
  47. [process.env.AWS_S3_USER_FILES_BUCKET_NAME]:
  48. AWS_S3_USER_FILES_STORAGE_CLASS,
  49. },
  50. }
  51. }
  52. function s3ConfigDefaultProviderCredentials() {
  53. return {
  54. ...s3BaseConfig(),
  55. }
  56. }
  57. function s3Stores() {
  58. return {
  59. user_files: process.env.AWS_S3_USER_FILES_BUCKET_NAME,
  60. template_files: process.env.AWS_S3_TEMPLATE_FILES_BUCKET_NAME,
  61. }
  62. }
  63. function gcsConfig() {
  64. return {
  65. endpoint: {
  66. apiEndpoint: process.env.GCS_API_ENDPOINT,
  67. projectId: 'fake',
  68. },
  69. directoryKeyRegex: /^[0-9a-fA-F]{24}\/[0-9a-fA-F]{24}/,
  70. unlockBeforeDelete: false, // fake-gcs does not support this
  71. deletedBucketSuffix: '-deleted',
  72. }
  73. }
  74. function gcsStores() {
  75. return {
  76. user_files: process.env.GCS_USER_FILES_BUCKET_NAME,
  77. template_files: process.env.GCS_TEMPLATE_FILES_BUCKET_NAME,
  78. }
  79. }
  80. function fsStores() {
  81. return {
  82. user_files: Path.resolve(__dirname, '../../../user_files'),
  83. template_files: Path.resolve(__dirname, '../../../template_files'),
  84. }
  85. }
  86. function fallbackStores(primaryConfig, fallbackConfig) {
  87. return {
  88. [primaryConfig.user_files]: fallbackConfig.user_files,
  89. [primaryConfig.template_files]: fallbackConfig.template_files,
  90. }
  91. }
  92. const BackendSettings = {
  93. SHARD_01_FSPersistor: {
  94. backend: 'fs',
  95. stores: fsStores(),
  96. },
  97. SHARD_01_S3Persistor: {
  98. backend: 's3',
  99. s3: s3Config(),
  100. stores: s3Stores(),
  101. },
  102. SHARD_01_S3PersistorDefaultProviderCredentials: {
  103. backend: 's3',
  104. s3: s3ConfigDefaultProviderCredentials(),
  105. stores: s3Stores(),
  106. },
  107. SHARD_01_GcsPersistor: {
  108. backend: 'gcs',
  109. gcs: gcsConfig(),
  110. stores: gcsStores(),
  111. },
  112. SHARD_01_PerProjectEncryptedS3Persistor: {
  113. backend: 's3SSEC',
  114. s3SSEC: s3SSECConfig(),
  115. stores: s3Stores(),
  116. },
  117. SHARD_02_FallbackS3ToFSPersistor: {
  118. backend: 's3',
  119. s3: s3Config(),
  120. stores: s3Stores(),
  121. fallback: {
  122. backend: 'fs',
  123. buckets: fallbackStores(s3Stores(), fsStores()),
  124. },
  125. },
  126. SHARD_02_FallbackFSToS3Persistor: {
  127. backend: 'fs',
  128. s3: s3Config(),
  129. stores: fsStores(),
  130. fallback: {
  131. backend: 's3',
  132. buckets: fallbackStores(fsStores(), s3Stores()),
  133. },
  134. },
  135. SHARD_03_FallbackGcsToS3Persistor: {
  136. backend: 'gcs',
  137. gcs: gcsConfig(),
  138. stores: gcsStores(),
  139. s3: s3Config(),
  140. fallback: {
  141. backend: 's3',
  142. buckets: fallbackStores(gcsStores(), s3Stores()),
  143. },
  144. },
  145. SHARD_03_FallbackS3ToGcsPersistor: {
  146. backend: 's3',
  147. // can use the same bucket names for gcs and s3 (in tests)
  148. stores: s3Stores(),
  149. s3: s3Config(),
  150. gcs: gcsConfig(),
  151. fallback: {
  152. backend: 'gcs',
  153. buckets: fallbackStores(s3Stores(), gcsStores()),
  154. },
  155. },
  156. }
  157. function checkForUnexpectedTestFile() {
  158. const awareOfSharding = [
  159. 'FilestoreApp.js',
  160. 'FilestoreTests.js',
  161. 'TestConfig.js',
  162. 'TestHelper.js',
  163. ]
  164. for (const file of fs.readdirSync(__dirname).sort()) {
  165. if (!awareOfSharding.includes(file)) {
  166. throw new Error(
  167. `Found new test file ${file}: All tests must be aware of the SHARD_ prefix.`
  168. )
  169. }
  170. }
  171. }
  172. checkForUnexpectedTestFile()
  173. module.exports = {
  174. AWS_S3_USER_FILES_STORAGE_CLASS,
  175. BackendSettings,
  176. s3Config,
  177. s3SSECConfig,
  178. }