From 3aaef3b3dd429baed168181b71f8d7ebdfdc120c Mon Sep 17 00:00:00 2001 From: Mathieu Fenniak Date: Fri, 23 Jan 2026 21:29:47 +0100 Subject: [PATCH] [v14.0/forgejo] fix: don't clobber authorized_keys file during installation (#10948) (#11009) **Backport**: https://codeberg.org/forgejo/forgejo/pulls/10948 (cherry picked from commit c52ecd22589a35577afd3248d48a96a292f4e1d5) Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/10948 Reviewed-by: 0ko <0ko@noreply.codeberg.org> Co-authored-by: Mathieu Fenniak Co-committed-by: Mathieu Fenniak ## Checklist The [contributor guide](https://forgejo.org/docs/next/contributor/) contains information that will be helpful to first time contributors. There also are a few [conditions for merging Pull Requests in Forgejo repositories](https://codeberg.org/forgejo/governance/src/branch/main/PullRequestsAgreement.md). You are also welcome to join the [Forgejo development chatroom](https://matrix.to/#/#forgejo-development:matrix.org). ### Tests - I added test coverage for Go changes... - [ ] in their respective `*_test.go` for unit tests. - [ ] in the `tests/integration` directory if it involves interactions with a live Forgejo server. - I added test coverage for JavaScript changes... - [ ] in `web_src/js/*.test.js` if it can be unit tested. - [ ] in `tests/e2e/*.test.e2e.js` if it requires interactions with a live Forgejo server (see also the [developer guide for JavaScript testing](https://codeberg.org/forgejo/forgejo/src/branch/forgejo/tests/e2e/README.md#end-to-end-tests)). ### Documentation - [ ] I created a pull request [to the documentation](https://codeberg.org/forgejo/docs) to explain to Forgejo users how to use this change. - [ ] I did not document these changes and I do not expect someone else to do it. ### Release notes - [ ] This change will be noticed by a Forgejo user or admin (feature, bug fix, performance, etc.). I suggest to include a release note for this change. - [ ] This change is not visible to a Forgejo user or admin (refactor, dependency upgrade, etc.). I think there is no need to add a release note for this change. *The decision if the pull request will be shown in the release notes is up to the mergers / release team.* The content of the `release-notes/.md` file will serve as the basis for the release notes. If the file does not exist, the title of the pull request will be used instead. Reviewed-on: https://codeberg.org/forgejo/forgejo/pulls/11009 Reviewed-by: 0ko <0ko@noreply.codeberg.org> --- modules/ssh/init.go | 4 +- options/locale_next/locale_en-US.json | 496 +++++++++++++------------- routers/init.go | 5 - routers/install/install.go | 20 ++ 4 files changed, 272 insertions(+), 253 deletions(-) diff --git a/modules/ssh/init.go b/modules/ssh/init.go index 432cda0c13..ebc17de69c 100644 --- a/modules/ssh/init.go +++ b/modules/ssh/init.go @@ -85,7 +85,9 @@ func Init(ctx context.Context) error { detailConcat := strings.Join(unexpectedKeys, "\n\t") log.Fatal("An unexpected ssh public key was discovered. Forgejo will shutdown to require this to be fixed. Fix by either:\n"+ "Option 1: Delete the file %s, and Forgejo will recreate it with only expected ssh public keys.\n"+ - "Option 2: Permit unexpected keys by setting [server].SSH_ALLOW_UNEXPECTED_AUTHORIZED_KEYS=true in Forgejo's config file.\n\t"+ + "Option 2: Permit unexpected keys by setting [server].SSH_ALLOW_UNEXPECTED_AUTHORIZED_KEYS=true in Forgejo's config file.\n"+ + "Option 3: If unused, disable SSH support by setting [server].DISABLE_SSH=true in Forgejo's config file.\n"+ + "\t"+ detailConcat, filepath.Join(setting.SSH.RootPath, "authorized_keys")) } } diff --git a/options/locale_next/locale_en-US.json b/options/locale_next/locale_en-US.json index 51920dda8f..90133f36ff 100644 --- a/options/locale_next/locale_en-US.json +++ b/options/locale_next/locale_en-US.json @@ -1,252 +1,254 @@ { "home.welcome.no_activity": "No activity", - "home.welcome.activity_hint": "There is nothing in your feed yet. Your actions and activity from repositories that you watch will show up here.", - "home.explore_repos": "Explore repositories", - "home.explore_users": "Explore users", - "home.explore_orgs": "Explore organizations", - "fork.n_forks": { - "one": "%s fork", - "other": "%s forks" - }, - "stars.list.none": "No one starred this repo.", - "stars.n_stars": { - "one": "%s star", - "other": "%s stars" - }, - "watch.list.none": "No one is watching this repo.", - "watch.n_watchers": { - "one": "%s watcher", - "other": "%s watchers" - }, - "followers.incoming.list.self.none": "No one is following your profile.", - "followers.incoming.list.none": "No one is following this user.", - "followers.outgoing.list.self.none": "You are not following anyone.", - "followers.outgoing.list.none": "%s isn't following anyone.", - "relativetime.now": "now", - "relativetime.future": "in future", - "relativetime.mins": { - "one": "%d minute ago", - "other": "%d minutes ago" - }, - "relativetime.hours": { - "one": "%d hour ago", - "other": "%d hours ago" - }, - "relativetime.days": { - "one": "%d day ago", - "other": "%d days ago" - }, - "relativetime.weeks": { - "one": "%d week ago", - "other": "%d weeks ago" - }, - "relativetime.months": { - "one": "%d month ago", - "other": "%d months ago" - }, - "relativetime.years": { - "one": "%d year ago", - "other": "%d years ago" - }, - "relativetime.1day": "yesterday", - "relativetime.2days": "two days ago", - "relativetime.1week": "last week", - "relativetime.2weeks": "two weeks ago", - "relativetime.1month": "last month", - "relativetime.2months": "two months ago", - "relativetime.1year": "last year", - "relativetime.2years": "two years ago", - "repo.issues.filter_poster.hint": "Filter by the author", - "repo.issues.filter_assignee.hint": "Filter by assigned user", - "repo.issues.filter_reviewers.hint": "Filter by user who reviewed", - "repo.issues.filter_mention.hint": "Filter by mentioned user", - "repo.issues.filter_modified.hint": "Filter by last modified date", - "repo.issues.filter_sort.hint": "Sort by: created/comments/updated/deadline", - "issues.updated": "updated %s", - "repo.pulls.poster_manage_approval": "Manage approval", - "repo.pulls.poster_requires_approval": "Some workflows are waiting to be reviewed.", - "repo.pulls.poster_requires_approval.tooltip": "The author of this pull request is not trusted to run workflows triggered by a pull request created from a forked repository or with AGit. The workflows triggered by a `pull_request` event will not run until they are approved.", - "repo.pulls.poster_is_trusted": "The author of this pull request is always trusted to run workflows.", - "repo.pulls.poster_is_trusted.tooltip": "The author of this pull request is explicitly trusted to run workflows triggered by `pull_request` events.", - "repo.pulls.poster_trust_deny": "Deny", - "repo.pulls.poster_trust_deny.tooltip": "The workflows waiting approval will be canceled.", - "repo.pulls.poster_trust_once": "Approve once", - "repo.pulls.poster_trust_once.tooltip": "The workflows triggered by a `pull_request` event will run on this commit but will need to be approved for all future commits pushed to this pull request.", - "repo.pulls.poster_trust_always": "Approve always", - "repo.pulls.poster_trust_always.tooltip": "The workflows triggered by a `pull_request` event will run on this commit and there will be no need to approve runs from this pull request or future pull requests authored by the same user.", - "repo.pulls.poster_trust_revoke": "Revoke", - "repo.pulls.poster_trust_revoke.tooltip": "The author of this pull request will no longer be trusted to run workflows triggered by a `pull_request` event, each run will have to be manually approved.", - "repo.pulls.already_merged": "Merge failed: This pull request has already been merged.", - "repo.pulls.merged_title_desc": { - "one": "merged %[1]d commit from %[2]s into %[3]s %[4]s", - "other": "merged %[1]d commits from %[2]s into %[3]s %[4]s" - }, - "repo.pulls.title_desc": { - "one": "wants to merge %[1]d commit from %[2]s into %[3]s", - "other": "wants to merge %[1]d commits from %[2]s into %[3]s" - }, - "repo.pulls.maintainers_can_edit": "Maintainers can edit this pull request.", - "repo.pulls.maintainers_cannot_edit": "Maintainers cannot edit this pull request.", - "repo.form.cannot_create": "All spaces in which you can create repositories have reached the limit of repositories.", - "migrate.form.error.url_credentials": "The URL contains credentials, put them in the username and password fields respectively", - "migrate.github.description": "Migrate data from github.com or GitHub Enterprise server.", - "migrate.git.description": "Migrate a repository only from any Git service.", - "migrate.gitea.description": "Migrate data from gitea.com or other Gitea instances.", - "migrate.gitlab.description": "Migrate data from gitlab.com or other GitLab instances.", - "migrate.gogs.description": "Migrate data from notabug.org or other Gogs instances.", - "migrate.onedev.description": "Migrate data from code.onedev.io or other OneDev instances.", - "migrate.gitbucket.description": "Migrate data from GitBucket instances.", - "migrate.codebase.description": "Migrate data from codebasehq.com.", - "migrate.forgejo.description": "Migrate data from codeberg.org or other Forgejo instances.", - "repo.issue_indexer.title": "Issue Indexer", - "search.milestone_kind": "Search milestones…", - "search.syntax": "Search syntax", - "search.fuzzy": "Fuzzy", - "search.fuzzy_tooltip": "Include results is an approximate match to the search term", - "repo.settings.push_mirror.branch_filter.label": "Branch filter (optional)", - "repo.settings.push_mirror.branch_filter.description": "Branches to be mirrored. Leave blank to mirror all branches. See %[2]s documentation for syntax. Examples: main, release/*", - "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini.", - "themes.names.forgejo-auto": "Forgejo (follow system theme)", - "themes.names.forgejo-light": "Forgejo light", - "themes.names.forgejo-dark": "Forgejo dark", - "error.not_found.title": "Page not found", - "warning.repository.out_of_sync": "The database representation of this repository is out of synchronization. If this warning is still shown after pushing a commit to this repository contact the administrator.", - "alert.asset_load_failed": "Failed to load asset files from {path}. Please make sure the asset files can be accessed.", - "alert.range_error": " must be a number between %[1]s and %[2]s.", - "install.invalid_lfs_path": "Unable to create the LFS root at the specified path: %[1]s", - "profile.actions.tooltip": "More actions", - "profile.edit.link": "Edit profile", - "feed.atom.link": "Atom feed", - "keys.ssh.link": "SSH keys", - "keys.gpg.link": "GPG keys", - "keys.verify.token.hint": "The token is only valid for 1 minute. Get a new one if it expired.", - "admin.config.moderation_config": "Moderation configuration", - "admin.moderation.moderation_reports": "Moderation reports", - "admin.moderation.reports": "Reports", - "admin.moderation.no_open_reports": "There are currently no open reports.", - "admin.moderation.deleted_content_ref": "Reported content with type %[1]v and id %[2]d no longer exists", - "moderation.report.mark_as_handled": "Mark as handled", - "moderation.report.mark_as_ignored": "Mark as ignored", - "moderation.action.account.delete": "Delete account", - "moderation.action.account.suspend": "Suspend account", - "moderation.action.repo.delete": "Delete repository", - "moderation.action.issue.delete": "Delete issue", - "moderation.action.comment.delete": "Delete comment", - "moderation.unknown_action": "Unknown action", - "moderation.users.cannot_suspend_self": "You cannot suspend yourself.", - "moderation.users.cannot_suspend_admins": "Users with admin privileges cannot be suspended.", - "moderation.users.cannot_suspend_org": "Organizations cannot be suspended.", - "moderation.users.already_suspended": "User account is already suspended.", - "moderation.users.suspend_success": "The user account has been suspended.", - "moderation.users.cannot_delete_admins": "Users with admin privileges cannot be deleted.", - "moderation.issue.deletion_success": "The issue has been deleted.", - "moderation.comment.deletion_success": "The comment has been deleted.", - "moderation.report_abuse": "Report abuse", - "moderation.report_content": "Report content", - "moderation.report_abuse_form.header": "Report abuse to administrator", - "moderation.report_abuse_form.details": "This form should be used to report users who create spam profiles, repositories, issues, comments or behave inappropriately.", - "moderation.report_abuse_form.invalid": "Invalid arguments", - "moderation.report_abuse_form.already_reported": "You've already reported this content", - "moderation.abuse_category": "Category", - "moderation.abuse_category.placeholder": "Select a category", - "moderation.abuse_category.spam": "Spam", - "moderation.abuse_category.malware": "Malware", - "moderation.abuse_category.illegal_content": "Illegal content", - "moderation.abuse_category.other_violations": "Other violations of platform rules", - "moderation.report_remarks": "Remarks", - "moderation.report_remarks.placeholder": "Please provide some details regarding the abuse you are reporting.", - "moderation.submit_report": "Submit report", - "moderation.reporting_failed": "Unable to submit the new abuse report: %v", - "moderation.reported_thank_you": "Thank you for your report. The administration has been made aware of it.", - "mail.actions.successful_run_after_failure_subject": "Workflow %[1]s recovered in repository %[2]s", - "mail.actions.not_successful_run_subject": "Workflow %[1]s failed in repository %[2]s", - "mail.actions.successful_run_after_failure": "Workflow %[1]s recovered in repository %[2]s", - "mail.actions.not_successful_run": "Workflow %[1]s failed in repository %[2]s", - "mail.actions.run_info_cur_status": "This Run's Status: %[1]s (just updated from %[2]s)", - "mail.actions.run_info_previous_status": "Previous Run's Status: %[1]s", - "mail.actions.run_info_sha": "Commit: %[1]s", - "mail.actions.run_info_trigger": "Triggered because: %[1]s by: %[2]s", - "mail.issue.action.close_by_commit": "%[1]s closed %[2]s in commit %[3]s.", - "repo.diff.commit.next-short": "Next", - "repo.diff.commit.previous-short": "Prev", - "discussion.locked": "This discussion has been locked. Commenting is limited to contributors.", - "discussion.sidebar.reference": "Reference", - "editor.textarea.tab_hint": "Line already indented. Press Tab again or Escape to leave the editor.", - "editor.textarea.shift_tab_hint": "No indentation on this line. Press Shift + Tab again or Escape to leave the editor.", - "admin.auths.allow_username_change": "Allow username change", - "admin.auths.allow_username_change.description": "Allow users to change their username in the profile settings", - "admin.dashboard.cleanup_offline_runners": "Cleanup offline runners", - "admin.dashboard.remove_resolved_reports": "Remove resolved reports", - "admin.dashboard.actions_action_user": "Revoke Forgejo Actions trust for inactive users", - "admin.dashboard.transfer_lingering_logs": "Transfer actions logs of finished actions jobs from the database to storage", - "admin.config.security": "Security configuration", - "admin.config.global_2fa_requirement.title": "Global two-factor requirement", - "admin.config.global_2fa_requirement.none": "No", - "admin.config.global_2fa_requirement.all": "All users", - "admin.config.global_2fa_requirement.admin": "Administrators", - "settings.visibility.description": "Profile visibility affects others' ability to access your non-private repositories. Learn more.", - "settings.twofa_unroll_unavailable": "Two-factor authentication is required for your account and cannot be disabled.", - "settings.twofa_reenroll": "Re-enroll two-factor authentication", - "settings.twofa_reenroll.description": "Re-enroll your two-factor authentication", - "settings.must_enable_2fa": "This Forgejo instance requires users to enable two-factor authentication before they can access their accounts.", - "error.must_enable_2fa": "This Forgejo instance requires users to enable two-factor authentication before they can access their accounts. Enable it at: %s", - "avatar.constraints_hint": "Custom avatar may not exceed %[1]s in size or be larger than %[2]dx%[3]d pixels", - "user.ghost.tooltip": "This user has been deleted, or cannot be matched.", - "og.repo.summary_card.alt_description": "Summary card of repository %[1]s, described as: %[2]s", - "repo.commit.load_tags_failed": "Load tags failed because of internal error", - "compare.branches.title": "Compare branches", - "migrate.pagure.description": "Migrate data from pagure.io or other Pagure instances.", - "migrate.pagure.incorrect_url": "Incorrect source repository URL has been provided", - "migrate.pagure.project_url": "Pagure project URL", - "migrate.pagure.project_example": "The Pagure project URL, e.g. https://pagure.io/pagure", - "migrate.pagure.token_label": "Pagure API Token", - "migrate.pagure.private_issues.summary": "Private Issues (Optional)", - "migrate.pagure.private_issues.description": "This feature is designed to create a second repository containing only private issues from your Pagure project for archive purposes. First, perform a normal migration (without a token) to import all public content. Then, if you have private issues to preserve, create a separate repository using this token option to archive those private issues.", - "migrate.pagure.private_issues.warning": "Be sure to set the repository visibility above to Private if you are using the API key to import private issues. This prevents accidentally exposing private content in a public repository.", - "migrate.pagure.token.placeholder": "Only for creating private issues archive", - "release.n_downloads": { - "one": "%s download", - "other": "%s downloads" - }, - "actions.status.diagnostics.waiting": { - "one": "Waiting for a runner with the following label: %s", - "other": "Waiting for a runner with the following labels: %s" - }, - "actions.runs.run_attempt_label": "Run attempt #%[1]s (%[2]s)", - "actions.runs.viewing_out_of_date_run": "You are viewing an out-of-date run of this job that was executed %[1]s.", - "actions.runs.view_most_recent_run": "View most recent run", - "actions.workflow.job_parsing_error": "Unable to parse jobs in workflow: %v", - "actions.workflow.event_detection_error": "Unable to parse supported events in workflow: %v", - "actions.workflow.persistent_incomplete_matrix": "Unable to evaluate `strategy.matrix` of job %[1]s due to a `needs` expression that was invalid. It may reference a job that is not in it's 'needs' list (%[2]s), or an output that doesn't exist on one of those jobs.", - "actions.workflow.incomplete_matrix_missing_job": "Unable to evaluate `strategy.matrix` of job %[1]s: job %[2]s is not in the `needs` list of job %[1]s (%[3]s).", + "home.welcome.activity_hint": "There is nothing in your feed yet. Your actions and activity from repositories that you watch will show up here.", + "home.explore_repos": "Explore repositories", + "home.explore_users": "Explore users", + "home.explore_orgs": "Explore organizations", + "fork.n_forks": { + "one": "%s fork", + "other": "%s forks" + }, + "stars.list.none": "No one starred this repo.", + "stars.n_stars": { + "one": "%s star", + "other": "%s stars" + }, + "watch.list.none": "No one is watching this repo.", + "watch.n_watchers": { + "one": "%s watcher", + "other": "%s watchers" + }, + "followers.incoming.list.self.none": "No one is following your profile.", + "followers.incoming.list.none": "No one is following this user.", + "followers.outgoing.list.self.none": "You are not following anyone.", + "followers.outgoing.list.none": "%s isn't following anyone.", + "relativetime.now": "now", + "relativetime.future": "in future", + "relativetime.mins": { + "one": "%d minute ago", + "other": "%d minutes ago" + }, + "relativetime.hours": { + "one": "%d hour ago", + "other": "%d hours ago" + }, + "relativetime.days": { + "one": "%d day ago", + "other": "%d days ago" + }, + "relativetime.weeks": { + "one": "%d week ago", + "other": "%d weeks ago" + }, + "relativetime.months": { + "one": "%d month ago", + "other": "%d months ago" + }, + "relativetime.years": { + "one": "%d year ago", + "other": "%d years ago" + }, + "relativetime.1day": "yesterday", + "relativetime.2days": "two days ago", + "relativetime.1week": "last week", + "relativetime.2weeks": "two weeks ago", + "relativetime.1month": "last month", + "relativetime.2months": "two months ago", + "relativetime.1year": "last year", + "relativetime.2years": "two years ago", + "repo.issues.filter_poster.hint": "Filter by the author", + "repo.issues.filter_assignee.hint": "Filter by assigned user", + "repo.issues.filter_reviewers.hint": "Filter by user who reviewed", + "repo.issues.filter_mention.hint": "Filter by mentioned user", + "repo.issues.filter_modified.hint": "Filter by last modified date", + "repo.issues.filter_sort.hint": "Sort by: created/comments/updated/deadline", + "issues.updated": "updated %s", + "repo.pulls.poster_manage_approval": "Manage approval", + "repo.pulls.poster_requires_approval": "Some workflows are waiting to be reviewed.", + "repo.pulls.poster_requires_approval.tooltip": "The author of this pull request is not trusted to run workflows triggered by a pull request created from a forked repository or with AGit. The workflows triggered by a `pull_request` event will not run until they are approved.", + "repo.pulls.poster_is_trusted": "The author of this pull request is always trusted to run workflows.", + "repo.pulls.poster_is_trusted.tooltip": "The author of this pull request is explicitly trusted to run workflows triggered by `pull_request` events.", + "repo.pulls.poster_trust_deny": "Deny", + "repo.pulls.poster_trust_deny.tooltip": "The workflows waiting approval will be canceled.", + "repo.pulls.poster_trust_once": "Approve once", + "repo.pulls.poster_trust_once.tooltip": "The workflows triggered by a `pull_request` event will run on this commit but will need to be approved for all future commits pushed to this pull request.", + "repo.pulls.poster_trust_always": "Approve always", + "repo.pulls.poster_trust_always.tooltip": "The workflows triggered by a `pull_request` event will run on this commit and there will be no need to approve runs from this pull request or future pull requests authored by the same user.", + "repo.pulls.poster_trust_revoke": "Revoke", + "repo.pulls.poster_trust_revoke.tooltip": "The author of this pull request will no longer be trusted to run workflows triggered by a `pull_request` event, each run will have to be manually approved.", + "repo.pulls.already_merged": "Merge failed: This pull request has already been merged.", + "repo.pulls.merged_title_desc": { + "one": "merged %[1]d commit from %[2]s into %[3]s %[4]s", + "other": "merged %[1]d commits from %[2]s into %[3]s %[4]s" + }, + "repo.pulls.title_desc": { + "one": "wants to merge %[1]d commit from %[2]s into %[3]s", + "other": "wants to merge %[1]d commits from %[2]s into %[3]s" + }, + "repo.pulls.maintainers_can_edit": "Maintainers can edit this pull request.", + "repo.pulls.maintainers_cannot_edit": "Maintainers cannot edit this pull request.", + "repo.form.cannot_create": "All spaces in which you can create repositories have reached the limit of repositories.", + "migrate.form.error.url_credentials": "The URL contains credentials, put them in the username and password fields respectively", + "migrate.github.description": "Migrate data from github.com or GitHub Enterprise server.", + "migrate.git.description": "Migrate a repository only from any Git service.", + "migrate.gitea.description": "Migrate data from gitea.com or other Gitea instances.", + "migrate.gitlab.description": "Migrate data from gitlab.com or other GitLab instances.", + "migrate.gogs.description": "Migrate data from notabug.org or other Gogs instances.", + "migrate.onedev.description": "Migrate data from code.onedev.io or other OneDev instances.", + "migrate.gitbucket.description": "Migrate data from GitBucket instances.", + "migrate.codebase.description": "Migrate data from codebasehq.com.", + "migrate.forgejo.description": "Migrate data from codeberg.org or other Forgejo instances.", + "repo.issue_indexer.title": "Issue Indexer", + "search.milestone_kind": "Search milestones…", + "search.syntax": "Search syntax", + "search.fuzzy": "Fuzzy", + "search.fuzzy_tooltip": "Include results is an approximate match to the search term", + "repo.settings.push_mirror.branch_filter.label": "Branch filter (optional)", + "repo.settings.push_mirror.branch_filter.description": "Branches to be mirrored. Leave blank to mirror all branches. See %[2]s documentation for syntax. Examples: main, release/*", + "incorrect_root_url": "This Forgejo instance is configured to be served on \"%s\". You are currently viewing Forgejo through a different URL, which may cause parts of the application to break. The canonical URL is controlled by Forgejo admins via the ROOT_URL setting in the app.ini.", + "themes.names.forgejo-auto": "Forgejo (follow system theme)", + "themes.names.forgejo-light": "Forgejo light", + "themes.names.forgejo-dark": "Forgejo dark", + "error.not_found.title": "Page not found", + "warning.repository.out_of_sync": "The database representation of this repository is out of synchronization. If this warning is still shown after pushing a commit to this repository contact the administrator.", + "alert.asset_load_failed": "Failed to load asset files from {path}. Please make sure the asset files can be accessed.", + "alert.range_error": " must be a number between %[1]s and %[2]s.", + "install.invalid_lfs_path": "Unable to create the LFS root at the specified path: %[1]s", + "profile.actions.tooltip": "More actions", + "profile.edit.link": "Edit profile", + "feed.atom.link": "Atom feed", + "keys.ssh.link": "SSH keys", + "keys.gpg.link": "GPG keys", + "keys.verify.token.hint": "The token is only valid for 1 minute. Get a new one if it expired.", + "admin.config.moderation_config": "Moderation configuration", + "admin.moderation.moderation_reports": "Moderation reports", + "admin.moderation.reports": "Reports", + "admin.moderation.no_open_reports": "There are currently no open reports.", + "admin.moderation.deleted_content_ref": "Reported content with type %[1]v and id %[2]d no longer exists", + "moderation.report.mark_as_handled": "Mark as handled", + "moderation.report.mark_as_ignored": "Mark as ignored", + "moderation.action.account.delete": "Delete account", + "moderation.action.account.suspend": "Suspend account", + "moderation.action.repo.delete": "Delete repository", + "moderation.action.issue.delete": "Delete issue", + "moderation.action.comment.delete": "Delete comment", + "moderation.unknown_action": "Unknown action", + "moderation.users.cannot_suspend_self": "You cannot suspend yourself.", + "moderation.users.cannot_suspend_admins": "Users with admin privileges cannot be suspended.", + "moderation.users.cannot_suspend_org": "Organizations cannot be suspended.", + "moderation.users.already_suspended": "User account is already suspended.", + "moderation.users.suspend_success": "The user account has been suspended.", + "moderation.users.cannot_delete_admins": "Users with admin privileges cannot be deleted.", + "moderation.issue.deletion_success": "The issue has been deleted.", + "moderation.comment.deletion_success": "The comment has been deleted.", + "moderation.report_abuse": "Report abuse", + "moderation.report_content": "Report content", + "moderation.report_abuse_form.header": "Report abuse to administrator", + "moderation.report_abuse_form.details": "This form should be used to report users who create spam profiles, repositories, issues, comments or behave inappropriately.", + "moderation.report_abuse_form.invalid": "Invalid arguments", + "moderation.report_abuse_form.already_reported": "You've already reported this content", + "moderation.abuse_category": "Category", + "moderation.abuse_category.placeholder": "Select a category", + "moderation.abuse_category.spam": "Spam", + "moderation.abuse_category.malware": "Malware", + "moderation.abuse_category.illegal_content": "Illegal content", + "moderation.abuse_category.other_violations": "Other violations of platform rules", + "moderation.report_remarks": "Remarks", + "moderation.report_remarks.placeholder": "Please provide some details regarding the abuse you are reporting.", + "moderation.submit_report": "Submit report", + "moderation.reporting_failed": "Unable to submit the new abuse report: %v", + "moderation.reported_thank_you": "Thank you for your report. The administration has been made aware of it.", + "mail.actions.successful_run_after_failure_subject": "Workflow %[1]s recovered in repository %[2]s", + "mail.actions.not_successful_run_subject": "Workflow %[1]s failed in repository %[2]s", + "mail.actions.successful_run_after_failure": "Workflow %[1]s recovered in repository %[2]s", + "mail.actions.not_successful_run": "Workflow %[1]s failed in repository %[2]s", + "mail.actions.run_info_cur_status": "This Run's Status: %[1]s (just updated from %[2]s)", + "mail.actions.run_info_previous_status": "Previous Run's Status: %[1]s", + "mail.actions.run_info_sha": "Commit: %[1]s", + "mail.actions.run_info_trigger": "Triggered because: %[1]s by: %[2]s", + "mail.issue.action.close_by_commit": "%[1]s closed %[2]s in commit %[3]s.", + "repo.diff.commit.next-short": "Next", + "repo.diff.commit.previous-short": "Prev", + "discussion.locked": "This discussion has been locked. Commenting is limited to contributors.", + "discussion.sidebar.reference": "Reference", + "editor.textarea.tab_hint": "Line already indented. Press Tab again or Escape to leave the editor.", + "editor.textarea.shift_tab_hint": "No indentation on this line. Press Shift + Tab again or Escape to leave the editor.", + "admin.auths.allow_username_change": "Allow username change", + "admin.auths.allow_username_change.description": "Allow users to change their username in the profile settings", + "admin.dashboard.cleanup_offline_runners": "Cleanup offline runners", + "admin.dashboard.remove_resolved_reports": "Remove resolved reports", + "admin.dashboard.actions_action_user": "Revoke Forgejo Actions trust for inactive users", + "admin.dashboard.transfer_lingering_logs": "Transfer actions logs of finished actions jobs from the database to storage", + "admin.config.security": "Security configuration", + "admin.config.global_2fa_requirement.title": "Global two-factor requirement", + "admin.config.global_2fa_requirement.none": "No", + "admin.config.global_2fa_requirement.all": "All users", + "admin.config.global_2fa_requirement.admin": "Administrators", + "settings.visibility.description": "Profile visibility affects others' ability to access your non-private repositories. Learn more.", + "settings.twofa_unroll_unavailable": "Two-factor authentication is required for your account and cannot be disabled.", + "settings.twofa_reenroll": "Re-enroll two-factor authentication", + "settings.twofa_reenroll.description": "Re-enroll your two-factor authentication", + "settings.must_enable_2fa": "This Forgejo instance requires users to enable two-factor authentication before they can access their accounts.", + "error.must_enable_2fa": "This Forgejo instance requires users to enable two-factor authentication before they can access their accounts. Enable it at: %s", + "avatar.constraints_hint": "Custom avatar may not exceed %[1]s in size or be larger than %[2]dx%[3]d pixels", + "user.ghost.tooltip": "This user has been deleted, or cannot be matched.", + "og.repo.summary_card.alt_description": "Summary card of repository %[1]s, described as: %[2]s", + "repo.commit.load_tags_failed": "Load tags failed because of internal error", + "compare.branches.title": "Compare branches", + "migrate.pagure.description": "Migrate data from pagure.io or other Pagure instances.", + "migrate.pagure.incorrect_url": "Incorrect source repository URL has been provided", + "migrate.pagure.project_url": "Pagure project URL", + "migrate.pagure.project_example": "The Pagure project URL, e.g. https://pagure.io/pagure", + "migrate.pagure.token_label": "Pagure API Token", + "migrate.pagure.private_issues.summary": "Private Issues (Optional)", + "migrate.pagure.private_issues.description": "This feature is designed to create a second repository containing only private issues from your Pagure project for archive purposes. First, perform a normal migration (without a token) to import all public content. Then, if you have private issues to preserve, create a separate repository using this token option to archive those private issues.", + "migrate.pagure.private_issues.warning": "Be sure to set the repository visibility above to Private if you are using the API key to import private issues. This prevents accidentally exposing private content in a public repository.", + "migrate.pagure.token.placeholder": "Only for creating private issues archive", + "release.n_downloads": { + "one": "%s download", + "other": "%s downloads" + }, + "actions.status.diagnostics.waiting": { + "one": "Waiting for a runner with the following label: %s", + "other": "Waiting for a runner with the following labels: %s" + }, + "actions.runs.run_attempt_label": "Run attempt #%[1]s (%[2]s)", + "actions.runs.viewing_out_of_date_run": "You are viewing an out-of-date run of this job that was executed %[1]s.", + "actions.runs.view_most_recent_run": "View most recent run", + "actions.workflow.job_parsing_error": "Unable to parse jobs in workflow: %v", + "actions.workflow.event_detection_error": "Unable to parse supported events in workflow: %v", + "actions.workflow.persistent_incomplete_matrix": "Unable to evaluate `strategy.matrix` of job %[1]s due to a `needs` expression that was invalid. It may reference a job that is not in it's 'needs' list (%[2]s), or an output that doesn't exist on one of those jobs.", + "actions.workflow.incomplete_matrix_missing_job": "Unable to evaluate `strategy.matrix` of job %[1]s: job %[2]s is not in the `needs` list of job %[1]s (%[3]s).", "actions.workflow.incomplete_matrix_missing_output": "Unable to evaluate `strategy.matrix` of job %[1]s: job %[2]s does not have an output %[3]s.", - "actions.workflow.incomplete_matrix_unknown_cause": "Unable to evaluate `strategy.matrix` of job %[1]s: unknown error.", - "actions.workflow.incomplete_runson_missing_job": "Unable to evaluate `runs-on` of job %[1]s: job %[2]s is not in the `needs` list of job %[1]s (%[3]s).", + "actions.workflow.incomplete_matrix_unknown_cause": "Unable to evaluate `strategy.matrix` of job %[1]s: unknown error.", + "actions.workflow.incomplete_runson_missing_job": "Unable to evaluate `runs-on` of job %[1]s: job %[2]s is not in the `needs` list of job %[1]s (%[3]s).", "actions.workflow.incomplete_runson_missing_output": "Unable to evaluate `runs-on` of job %[1]s: job %[2]s does not have an output %[3]s.", - "actions.workflow.incomplete_runson_missing_matrix_dimension": "Unable to evaluate `runs-on` of job %[1]s: matrix dimension %[2]s does not exist.", - "actions.workflow.incomplete_runson_unknown_cause": "Unable to evaluate `runs-on` of job %[1]s: unknown error.", - "actions.workflow.pre_execution_error": "Workflow was not executed due to an error that blocked the execution attempt.", - "pulse.n_active_issues": { - "one": "%s active issue", - "other": "%s active issues" - }, - "pulse.n_active_prs": { - "one": "%s active pull request", - "other": "%s active pull requests" - }, - "teams.add_all_repos.modal.header": "Add all repositories", - "teams.remove_all_repos.modal.header": "Remove all repositories", - "admin.auths.oauth2_quota_group_claim_name": "Claim name providing group names for this source to be used for quota management. (Optional)", - "admin.auths.oauth2_quota_group_map": "Map claimed groups to quota groups. (Optional - requires claim name above)", - "admin.auths.oauth2_quota_group_map_removal": "Remove users from synchronized quota groups if user does not belong to corresponding group.", - "editor.search": "Search", - "editor.find_previous": "Previous find", - "editor.find_next": "Next find", - "editor.replace": "Replace", - "editor.replace_all": "Replace all", - "editor.toggle_case": "Toggle case sensitivity", - "editor.toggle_regex": "Toggle using regular expressions", - "editor.toggle_whole_word": "Toggle matching whole words", - "repo.view.gitmodules_too_large": "The .gitmodules file is too large and will be ignored (on API calls for instance)", - "meta.last_line": "Thank you for translating Forgejo! This line isn't seen by the users but it serves other purposes in the translation management. You can place a fun fact in the translation instead of translating it." + "actions.workflow.incomplete_runson_missing_matrix_dimension": "Unable to evaluate `runs-on` of job %[1]s: matrix dimension %[2]s does not exist.", + "actions.workflow.incomplete_runson_unknown_cause": "Unable to evaluate `runs-on` of job %[1]s: unknown error.", + "actions.workflow.pre_execution_error": "Workflow was not executed due to an error that blocked the execution attempt.", + "pulse.n_active_issues": { + "one": "%s active issue", + "other": "%s active issues" + }, + "pulse.n_active_prs": { + "one": "%s active pull request", + "other": "%s active pull requests" + }, + "teams.add_all_repos.modal.header": "Add all repositories", + "teams.remove_all_repos.modal.header": "Remove all repositories", + "admin.auths.oauth2_quota_group_claim_name": "Claim name providing group names for this source to be used for quota management. (Optional)", + "admin.auths.oauth2_quota_group_map": "Map claimed groups to quota groups. (Optional - requires claim name above)", + "admin.auths.oauth2_quota_group_map_removal": "Remove users from synchronized quota groups if user does not belong to corresponding group.", + "editor.search": "Search", + "editor.find_previous": "Previous find", + "editor.find_next": "Next find", + "editor.replace": "Replace", + "editor.replace_all": "Replace all", + "editor.toggle_case": "Toggle case sensitivity", + "editor.toggle_regex": "Toggle using regular expressions", + "editor.toggle_whole_word": "Toggle matching whole words", + "repo.view.gitmodules_too_large": "The .gitmodules file is too large and will be ignored (on API calls for instance)", + "install.ssh_authorized_keys_inspection_error": "Failed to inspect existing authorized_keys file: %v", + "install.ssh_authorized_keys_unexpected_key": "Enabling SSH for Forgejo conflicts with the file located at %s that contains existing SSH keys. Suggestions: use a dedicated system user for Forgejo, or disable SSH.", + "meta.last_line": "Thank you for translating Forgejo! This line isn't seen by the users but it serves other purposes in the translation management. You can place a fun fact in the translation instead of translating it." } diff --git a/routers/init.go b/routers/init.go index 6313d9a3ad..4fd708c47b 100644 --- a/routers/init.go +++ b/routers/init.go @@ -9,7 +9,6 @@ import ( "runtime" "forgejo.org/models" - asymkey_model "forgejo.org/models/asymkey" auth_model "forgejo.org/models/auth" "forgejo.org/modules/cache" "forgejo.org/modules/eventsource" @@ -95,10 +94,6 @@ func syncAppConfForGit(ctx context.Context) error { if updated { log.Info("re-sync repository hooks ...") mustInitCtx(ctx, repo_service.SyncRepositoryHooks) - - log.Info("re-write ssh public keys ...") - mustInitCtx(ctx, asymkey_model.RewriteAllPublicKeys) - return system.AppState.Set(ctx, runtimeState) } return nil diff --git a/routers/install/install.go b/routers/install/install.go index 63a3f965f4..243f4a8f19 100644 --- a/routers/install/install.go +++ b/routers/install/install.go @@ -15,6 +15,7 @@ import ( "strings" "time" + "forgejo.org/models/asymkey" "forgejo.org/models/db" db_install "forgejo.org/models/db/install" "forgejo.org/models/gitea_migrations" @@ -403,6 +404,25 @@ func SubmitInstall(ctx *context.Context) { } else { cfg.Section("server").Key("DISABLE_SSH").SetValue("false") cfg.Section("server").Key("SSH_PORT").SetValue(fmt.Sprint(form.SSHPort)) + + sshKeyErrors, err := asymkey.InspectPublicKeys(ctx) + if err != nil { + ctx.RenderWithErr(ctx.Tr("install.ssh_authorized_keys_inspection_error", err), tplInstall, &form) + return + } + + var authorizedKeysWillCauseFatalError bool + for _, finding := range sshKeyErrors { + if finding.Type == asymkey.InspectionResultUnexpectedKey { + // Any single finding of this type would cause `ssh.Init` to have a fatal error on Forgejo startup, so + // let's note it here while the install page is still usable and allow users to deal with it. + authorizedKeysWillCauseFatalError = true + } + } + if authorizedKeysWillCauseFatalError { + ctx.RenderWithErr(ctx.Tr("install.ssh_authorized_keys_unexpected_key", filepath.Join(setting.SSH.RootPath, "authorized_keys")), tplInstall, &form) + return + } } if form.LFSRootPath != "" {