diff --git a/custom/conf/app.example.ini b/custom/conf/app.example.ini index 6c8c85b87c..c0a3f3162a 100644 --- a/custom/conf/app.example.ini +++ b/custom/conf/app.example.ini @@ -2459,6 +2459,10 @@ LEVEL = Info ;ENABLE_SITEMAP = true ;; Enable/Disable RSS/Atom feed ;ENABLE_FEED = true +;; Terms of Service URL. If set, users will have to agree to the ToS during registration. +;TERMS_OF_SERVICE = /terms +;; Privacy Policy URL. If set, users will have to agree to the Privacy Policy during registration. +;PRIVACY_POLICY = /privacy ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; diff --git a/modules/setting/other.go b/modules/setting/other.go index db60cd2205..b5b4602be5 100644 --- a/modules/setting/other.go +++ b/modules/setting/other.go @@ -11,6 +11,8 @@ type OtherConfig struct { ShowFooterPoweredBy bool EnableFeed bool EnableSitemap bool + TermsOfServiceUrl string + PrivacyPolicyUrl string } var Other = OtherConfig{ @@ -19,6 +21,8 @@ var Other = OtherConfig{ ShowFooterPoweredBy: true, EnableSitemap: true, EnableFeed: true, + TermsOfServiceUrl: "", + PrivacyPolicyUrl: "", } func loadOtherFrom(rootCfg ConfigProvider) { diff --git a/modules/web/middleware/data.go b/modules/web/middleware/data.go index 4603e64052..33bc4664ff 100644 --- a/modules/web/middleware/data.go +++ b/modules/web/middleware/data.go @@ -53,6 +53,8 @@ func CommonTemplateContextData() ContextData { "ShowMilestonesDashboardPage": setting.Service.ShowMilestonesDashboardPage, "ShowFooterVersion": setting.Other.ShowFooterVersion, "DisableDownloadSourceArchives": setting.Repository.DisableDownloadSourceArchives, + "TermsOfServiceURL": setting.Other.TermsOfServiceUrl, + "PrivacyPolicyURL": setting.Other.PrivacyPolicyUrl, "EnableSwagger": setting.API.EnableSwagger, "EnableOpenIDSignIn": setting.Service.EnableOpenIDSignIn, diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini index d8e3f90777..bc45fad205 100644 --- a/options/locale/locale_en-US.ini +++ b/options/locale/locale_en-US.ini @@ -27,6 +27,8 @@ licenses = Licenses return_to_forgejo = Return to Forgejo toggle_menu = Toggle menu more_items = More items +terms_of_service = Terms of Service +privacy_policy = Privacy Policy username = Username email = Email address @@ -37,6 +39,8 @@ captcha = CAPTCHA twofa = Two-factor authentication twofa_scratch = Two-factor scratch code passcode = Passcode +consent.terms_of_service = I have read and agree to the Terms of Service +consent.privacy_policy = I have read and agree to the Privacy Policy webauthn_insert_key = Insert your security key webauthn_sign_in = Press the button on your security key. If your security key has no button, re-insert it. @@ -479,6 +483,7 @@ password_pwned_err = Could not complete request to HaveIBeenPwned last_admin = You cannot remove the last admin. There must be at least one admin. back_to_sign_in = Back to Sign in sign_in_openid = Proceed with OpenID +must_consent = You must agree to the Terms of Service and Privacy Policy to register an account. [mail] view_it_on = View it on %s diff --git a/routers/web/auth/auth.go b/routers/web/auth/auth.go index 3b4e62c429..e54083d4c1 100644 --- a/routers/web/auth/auth.go +++ b/routers/web/auth/auth.go @@ -448,6 +448,11 @@ func SignUpPost(ctx *context.Context) { return } + if !form.ConsentTerms || !form.ConsentPrivacy { + ctx.RenderWithErr(ctx.Tr("auth.must_consent"), tplSignUp, &form) + return + } + context.VerifyCaptcha(ctx, tplSignUp, form) if ctx.Written() { return diff --git a/services/forms/user_form.go b/services/forms/user_form.go index 8c95139e2c..5888bddf00 100644 --- a/services/forms/user_form.go +++ b/services/forms/user_form.go @@ -92,10 +92,12 @@ func (f *InstallForm) Validate(req *http.Request, errs binding.Errors) binding.E // RegisterForm form for registering type RegisterForm struct { - UserName string `binding:"Required;Username;MaxSize(40)"` - Email string `binding:"Required;MaxSize(254)"` - Password string `binding:"MaxSize(255)"` - Retype string + UserName string `binding:"Required;Username;MaxSize(40)"` + Email string `binding:"Required;MaxSize(254)"` + Password string `binding:"MaxSize(255)"` + Retype string + ConsentTerms bool + ConsentPrivacy bool } // Validate validates the fields diff --git a/templates/base/footer_content.tmpl b/templates/base/footer_content.tmpl index 133ebac33a..24d3857a5f 100644 --- a/templates/base/footer_content.tmpl +++ b/templates/base/footer_content.tmpl @@ -25,8 +25,9 @@ {{end}} + {{if .TermsOfServiceURL}}{{ctx.Locale.Tr "terms_of_service"}}{{end}} + {{if .PrivacyPolicyURL}}{{ctx.Locale.Tr "privacy_policy"}}{{end}} {{ctx.Locale.Tr "licenses"}} - {{if .EnableSwagger}}API{{end}} {{template "custom/extra_links_footer" .}} diff --git a/templates/user/auth/consent.tmpl b/templates/user/auth/consent.tmpl new file mode 100644 index 0000000000..02647fdf31 --- /dev/null +++ b/templates/user/auth/consent.tmpl @@ -0,0 +1,21 @@ +{{ if (.TermsOfServiceURL) }} +