i18n.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. // Copyright (C) 2023 Nicola Murino
  2. //
  3. // This program is free software: you can redistribute it and/or modify
  4. // it under the terms of the GNU Affero General Public License as published
  5. // by the Free Software Foundation, version 3.
  6. //
  7. // This program is distributed in the hope that it will be useful,
  8. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. // GNU Affero General Public License for more details.
  11. //
  12. // You should have received a copy of the GNU Affero General Public License
  13. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  14. package util
  15. import (
  16. "encoding/json"
  17. "errors"
  18. )
  19. // localization id for the Web frontend
  20. const (
  21. I18nSetupTitle = "title.setup"
  22. I18nLoginTitle = "title.login"
  23. I18nShareLoginTitle = "title.share_login"
  24. I18nFilesTitle = "title.files"
  25. I18nSharesTitle = "title.shares"
  26. I18nShareAddTitle = "title.add_share"
  27. I18nShareUpdateTitle = "title.update_share"
  28. I18nProfileTitle = "title.profile"
  29. I18nUsersTitle = "title.users"
  30. I18nGroupsTitle = "title.groups"
  31. I18nFoldersTitle = "title.folders"
  32. I18nChangePwdTitle = "title.change_password"
  33. I18n2FATitle = "title.two_factor_auth"
  34. I18nEditFileTitle = "title.edit_file"
  35. I18nViewFileTitle = "title.view_file"
  36. I18nForgotPwdTitle = "title.recovery_password"
  37. I18nResetPwdTitle = "title.reset_password"
  38. I18nSharedFilesTitle = "title.shared_files"
  39. I18nShareUploadTitle = "title.upload_to_share"
  40. I18nShareDownloadTitle = "title.download_shared_file"
  41. I18nShareAccessErrorTitle = "title.share_access_error"
  42. I18nInvalidAuthReqTitle = "title.invalid_auth_request"
  43. I18nError403Title = "title.error403"
  44. I18nError400Title = "title.error400"
  45. I18nError404Title = "title.error404"
  46. I18nError416Title = "title.error416"
  47. I18nError429Title = "title.error429"
  48. I18nError500Title = "title.error500"
  49. I18nErrorPDFTitle = "title.errorPDF"
  50. I18nErrorEditorTitle = "title.error_editor"
  51. I18nAddUserTitle = "title.add_user"
  52. I18nUpdateUserTitle = "title.update_user"
  53. I18nAddAdminTitle = "title.add_admin"
  54. I18nUpdateAdminTitle = "title.update_admin"
  55. I18nTemplateUserTitle = "title.template_user"
  56. I18nMaintenanceTitle = "title.maintenance"
  57. I18nConfigsTitle = "title.configs"
  58. I18nOAuth2Title = "title.oauth2_success"
  59. I18nOAuth2ErrorTitle = "title.oauth2_error"
  60. I18nSessionsTitle = "title.connections"
  61. I18nRolesTitle = "title.roles"
  62. I18nAdminsTitle = "title.admins"
  63. I18nIPListsTitle = "title.ip_lists"
  64. I18nAddIPListTitle = "title.add_ip_list"
  65. I18nUpdateIPListTitle = "title.update_ip_list"
  66. I18nDefenderTitle = "title.defender"
  67. I18nStatusTitle = "status.desc"
  68. I18nErrorSetupInstallCode = "setup.install_code_mismatch"
  69. I18nInvalidAuth = "general.invalid_auth_request"
  70. I18nError429Message = "general.error429"
  71. I18nError400Message = "general.error400"
  72. I18nError403Message = "general.error403"
  73. I18nError404Message = "general.error404"
  74. I18nError416Message = "general.error416"
  75. I18nError500Message = "general.error500"
  76. I18nErrorPDFMessage = "general.errorPDF"
  77. I18nErrorInvalidToken = "general.invalid_token"
  78. I18nErrorInvalidForm = "general.invalid_form"
  79. I18nErrorInvalidCredentials = "general.invalid_credentials"
  80. I18nErrorInvalidCSRF = "general.invalid_csrf"
  81. I18nErrorFsGeneric = "fs.err_generic"
  82. I18nErrorDirListGeneric = "fs.dir_list.err_generic"
  83. I18nErrorDirList403 = "fs.dir_list.err_403"
  84. I18nErrorDirList429 = "fs.dir_list.err_429"
  85. I18nErrorDirListUser = "fs.dir_list.err_user"
  86. I18nErrorFsValidation = "fs.err_validation"
  87. I18nErrorChangePwdRequiredFields = "change_pwd.required_fields"
  88. I18nErrorChangePwdNoMatch = "change_pwd.no_match"
  89. I18nErrorChangePwdGeneric = "change_pwd.generic"
  90. I18nErrorChangePwdNoDifferent = "change_pwd.no_different"
  91. I18nErrorChangePwdCurrentNoMatch = "change_pwd.current_no_match"
  92. I18nErrorChangePwdRequired = "change_pwd.required"
  93. I18nErrorUsernameRequired = "general.username_required"
  94. I18nErrorPasswordRequired = "general.password_required"
  95. I18nErrorPermissionsRequired = "general.permissions_required"
  96. I18nErrorGetUser = "general.err_user"
  97. I18nErrorPwdResetForbidded = "login.reset_pwd_forbidden"
  98. I18nErrorPwdResetNoEmail = "login.reset_pwd_no_email"
  99. I18nErrorPwdResetSendEmail = "login.reset_pwd_send_email_err"
  100. I18nErrorPwdResetGeneric = "login.reset_pwd_err_generic"
  101. I18nErrorProtocolForbidden = "general.err_protocol_forbidden"
  102. I18nErrorPwdLoginForbidden = "general.pwd_login_forbidden"
  103. I18nErrorIPForbidden = "general.ip_forbidden"
  104. I18nErrorConnectionForbidden = "general.connection_forbidden"
  105. I18nErrorReservedUsername = "user.username_reserved"
  106. I18nErrorInvalidEmail = "general.email_invalid"
  107. I18nErrorInvalidUser = "user.username_invalid"
  108. I18nErrorInvalidName = "user.name_invalid"
  109. I18nErrorHomeRequired = "user.home_required"
  110. I18nErrorHomeInvalid = "user.home_invalid"
  111. I18nErrorPubKeyInvalid = "user.pub_key_invalid"
  112. I18nErrorPrimaryGroup = "user.err_primary_group"
  113. I18nErrorDuplicateGroup = "user.err_duplicate_group"
  114. I18nErrorNoPermission = "user.no_permissions"
  115. I18nErrorNoRootPermission = "user.no_root_permissions"
  116. I18nErrorGenericPermission = "user.err_permissions_generic"
  117. I18nError2FAInvalid = "user.2fa_invalid"
  118. I18nErrorRecoveryCodesInvalid = "user.recovery_codes_invalid"
  119. I18nErrorFolderNameRequired = "general.foldername_required"
  120. I18nErrorFolderMountPathRequired = "user.folder_path_required"
  121. I18nErrorDuplicatedFolders = "user.folder_duplicated"
  122. I18nErrorOverlappedFolders = "user.folder_overlapped"
  123. I18nErrorFolderQuotaSizeInvalid = "user.folder_quota_size_invalid"
  124. I18nErrorFolderQuotaFileInvalid = "user.folder_quota_file_invalid"
  125. I18nErrorFolderQuotaInvalid = "user.folder_quota_invalid"
  126. I18nErrorPasswordComplexity = "general.err_password_complexity"
  127. I18nErrorIPFiltersInvalid = "user.ip_filters_invalid"
  128. I18nErrorSourceBWLimitInvalid = "user.src_bw_limits_invalid"
  129. I18nErrorShareExpirationInvalid = "user.share_expiration_invalid"
  130. I18nErrorFilePatternPathInvalid = "user.file_pattern_path_invalid"
  131. I18nErrorFilePatternDuplicated = "user.file_pattern_duplicated"
  132. I18nErrorFilePatternInvalid = "user.file_pattern_invalid"
  133. I18nErrorDisableActive2FA = "user.disable_active_2fa"
  134. I18nErrorPwdChangeConflict = "user.pwd_change_conflict"
  135. I18nErrorLoginAfterReset = "login.reset_ok_login_error"
  136. I18nErrorShareScope = "share.scope_invalid"
  137. I18nErrorShareMaxTokens = "share.max_tokens_invalid"
  138. I18nErrorShareExpiration = "share.expiration_invalid"
  139. I18nErrorShareNoPwd = "share.err_no_password"
  140. I18nErrorShareExpirationOutOfRange = "share.expiration_out_of_range"
  141. I18nErrorShareGeneric = "share.generic"
  142. I18nErrorNameRequired = "general.name_required"
  143. I18nErrorSharePathRequired = "share.path_required"
  144. I18nErrorShareWriteScope = "share.path_write_scope"
  145. I18nErrorShareNestedPaths = "share.nested_paths"
  146. I18nErrorShareExpirationPast = "share.expiration_past"
  147. I18nErrorInvalidIPMask = "general.allowed_ip_mask_invalid"
  148. I18nErrorShareUsage = "share.usage_exceed"
  149. I18nErrorShareExpired = "share.expired"
  150. I18nErrorLoginFromIPDenied = "login.ip_not_allowed"
  151. I18nError2FARequired = "login.two_factor_required"
  152. I18nErrorNoOIDCFeature = "general.no_oidc_feature"
  153. I18nErrorNoPermissions = "general.no_permissions"
  154. I18nErrorShareBrowsePaths = "share.browsable_multiple_paths"
  155. I18nErrorShareBrowseNoDir = "share.browsable_non_dir"
  156. I18nErrorShareInvalidPath = "share.invalid_path"
  157. I18nErrorPathInvalid = "general.path_invalid"
  158. I18nErrorQuotaRead = "general.err_quota_read"
  159. I18nErrorEditDir = "general.error_edit_dir"
  160. I18nErrorEditSize = "general.error_edit_size"
  161. I18nProfileUpdated = "general.profile_updated"
  162. I18nShareLoginOK = "general.share_ok"
  163. I18n2FADisabled = "2fa.disabled"
  164. I18nOIDCTokenExpired = "oidc.token_expired"
  165. I18nOIDCTokenInvalidAdmin = "oidc.token_invalid_webadmin"
  166. I18nOIDCTokenInvalidUser = "oidc.token_invalid_webclient"
  167. I18nOIDCErrTokenExchange = "oidc.token_exchange_err"
  168. I18nOIDCTokenInvalid = "oidc.token_invalid"
  169. I18nOIDCTokenInvalidRoleAdmin = "oidc.role_admin_err"
  170. I18nOIDCTokenInvalidRoleUser = "oidc.role_user_err"
  171. I18nOIDCErrGetUser = "oidc.get_user_err"
  172. I18nStorageLocal = "storage.local"
  173. I18nStorageLocalEncrypted = "storage.encrypted"
  174. I18nStorageS3 = "storage.s3"
  175. I18nStorageGCS = "storage.gcs"
  176. I18nStorageAzureBlob = "storage.azblob"
  177. I18nStorageSFTP = "storage.sftp"
  178. I18nStorageHTTP = "storage.http"
  179. I18nErrorInvalidQuotaSize = "user.invalid_quota_size"
  180. I18nErrorInvalidMaxFilesize = "filters.max_upload_size_invalid"
  181. I18nErrorInvalidHomeDir = "storage.home_dir_invalid"
  182. I18nErrorBucketRequired = "storage.bucket_required"
  183. I18nErrorRegionRequired = "storage.region_required"
  184. I18nErrorKeyPrefixInvalid = "storage.key_prefix_invalid"
  185. I18nErrorULPartSizeInvalid = "storage.ul_part_size_invalid"
  186. I18nErrorDLPartSizeInvalid = "storage.dl_part_size_invalid"
  187. I18nErrorULConcurrencyInvalid = "storage.ul_concurrency_invalid"
  188. I18nErrorDLConcurrencyInvalid = "storage.dl_concurrency_invalid"
  189. I18nErrorAccessKeyRequired = "storage.access_key_required"
  190. I18nErrorAccessSecretRequired = "storage.access_secret_required"
  191. I18nErrorFsCredentialsRequired = "storage.credentials_required"
  192. I18nErrorContainerRequired = "storage.container_required"
  193. I18nErrorAccountNameRequired = "storage.account_name_required"
  194. I18nErrorSASURLInvalid = "storage.sas_url_invalid"
  195. I18nErrorPassphraseRequired = "storage.passphrase_required"
  196. I18nErrorEndpointInvalid = "storage.endpoint_invalid"
  197. I18nErrorEndpointRequired = "storage.endpoint_required"
  198. I18nErrorFsUsernameRequired = "storage.username_required"
  199. I18nAddGroupTitle = "title.add_group"
  200. I18nUpdateGroupTitle = "title.update_group"
  201. I18nRoleAddTitle = "title.add_role"
  202. I18nRoleUpdateTitle = "title.update_role"
  203. I18nErrorInvalidTLSCert = "user.tls_cert_invalid"
  204. I18nAddFolderTitle = "title.add_folder"
  205. I18nUpdateFolderTitle = "title.update_folder"
  206. I18nTemplateFolderTitle = "title.template_folder"
  207. I18nErrorDuplicatedUsername = "general.duplicated_username"
  208. I18nErrorDuplicatedName = "general.duplicated_name"
  209. I18nErrorDuplicatedIPNet = "ip_list.duplicated"
  210. I18nErrorRoleAdminPerms = "admin.role_permissions"
  211. I18nBackupOK = "maintenance.backup_ok"
  212. I18nErrorFolderTemplate = "virtual_folders.template_no_folder"
  213. I18nErrorUserTemplate = "user.template_no_user"
  214. I18nConfigsOK = "general.configs_saved"
  215. I18nOAuth2ErrorVerifyState = "oauth2.auth_verify_error"
  216. I18nOAuth2ErrorValidateState = "oauth2.auth_validation_error"
  217. I18nOAuth2InvalidState = "oauth2.auth_invalid"
  218. I18nOAuth2ErrTokenExchange = "oauth2.token_exchange_err"
  219. I18nOAuth2ErrNoRefreshToken = "oauth2.no_refresh_token"
  220. I18nOAuth2OK = "oauth2.success"
  221. I18nErrorAdminSelfPerms = "admin.self_permissions"
  222. I18nErrorAdminSelfDisable = "admin.self_disable"
  223. I18nErrorAdminSelfRole = "admin.self_role"
  224. I18nErrorIpInvalid = "ip_list.ip_invalid"
  225. I18nErrorNetInvalid = "ip_list.net_invalid"
  226. I18nFTPTLSDisabled = "status.tls_disabled"
  227. I18nFTPTLSExplicit = "status.tls_explicit"
  228. I18nFTPTLSImplicit = "status.tls_implicit"
  229. I18nFTPTLSMixed = "status.tls_mixed"
  230. I18nErrorBackupFile = "maintenance.backup_invalid_file"
  231. I18nErrorRestore = "maintenance.restore_error"
  232. I18nErrorACMEGeneric = "acme.generic_error"
  233. I18nErrorSMTPRequiredFields = "smtp.err_required_fields"
  234. I18nErrorSMTPClientIDRequired = "smtp.client_id_required"
  235. I18nErrorSMTPClientSecretRequired = "smtp.client_secret_required"
  236. I18nErrorSMTPRefreshTokenRequired = "smtp.refresh_token_required"
  237. )
  238. // NewI18nError returns a I18nError wrappring the provided error
  239. func NewI18nError(err error, message string, options ...I18nErrorOption) *I18nError {
  240. var errI18n *I18nError
  241. if errors.As(err, &errI18n) {
  242. return errI18n
  243. }
  244. errI18n = &I18nError{
  245. err: err,
  246. Message: message,
  247. args: nil,
  248. }
  249. for _, opt := range options {
  250. opt(errI18n)
  251. }
  252. return errI18n
  253. }
  254. // I18nErrorOption defines a functional option type that allows to configure the I18nError.
  255. type I18nErrorOption func(*I18nError)
  256. // I18nErrorArgs is a functional option to set I18nError arguments.
  257. func I18nErrorArgs(args map[string]any) I18nErrorOption {
  258. return func(e *I18nError) {
  259. e.args = args
  260. }
  261. }
  262. // I18nError is an error wrapper that add a message to use for localization.
  263. type I18nError struct {
  264. err error
  265. Message string
  266. args map[string]any
  267. }
  268. // Error returns the wrapped error string.
  269. func (e *I18nError) Error() string {
  270. return e.err.Error()
  271. }
  272. // Unwrap returns the underlying error
  273. func (e *I18nError) Unwrap() error {
  274. return e.err
  275. }
  276. // Is reports if target matches
  277. func (e *I18nError) Is(target error) bool {
  278. if errors.Is(e.err, target) {
  279. return true
  280. }
  281. _, ok := target.(*I18nError)
  282. return ok
  283. }
  284. // HasArgs returns true if the error has i18n args.
  285. func (e *I18nError) HasArgs() bool {
  286. return len(e.args) > 0
  287. }
  288. // Args returns the provided args in JSON format
  289. func (e *I18nError) Args() string {
  290. if len(e.args) > 0 {
  291. data, err := json.Marshal(e.args)
  292. if err == nil {
  293. return string(data)
  294. }
  295. }
  296. return "{}"
  297. }