|
|
|
@ -15,7 +15,6 @@ import (
|
|
|
|
|
"os/exec" |
|
|
|
|
"path" |
|
|
|
|
"path/filepath" |
|
|
|
|
"regexp" |
|
|
|
|
"runtime" |
|
|
|
|
"strconv" |
|
|
|
|
"strings" |
|
|
|
@ -63,22 +62,6 @@ const (
|
|
|
|
|
LandingPageOrganizations LandingPage = "/explore/organizations" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// MarkupParser defines the external parser configured in ini
|
|
|
|
|
type MarkupParser struct { |
|
|
|
|
Enabled bool |
|
|
|
|
MarkupName string |
|
|
|
|
Command string |
|
|
|
|
FileExtensions []string |
|
|
|
|
IsInputFile bool |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// enumerates all the policy repository creating
|
|
|
|
|
const ( |
|
|
|
|
RepoCreatingLastUserVisibility = "last" |
|
|
|
|
RepoCreatingPrivate = "private" |
|
|
|
|
RepoCreatingPublic = "public" |
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
// enumerates all the types of captchas
|
|
|
|
|
const ( |
|
|
|
|
ImageCaptcha = "image" |
|
|
|
@ -181,113 +164,6 @@ var (
|
|
|
|
|
DBConnectRetries int |
|
|
|
|
DBConnectBackoff time.Duration |
|
|
|
|
|
|
|
|
|
// Repository settings
|
|
|
|
|
Repository = struct { |
|
|
|
|
AnsiCharset string |
|
|
|
|
ForcePrivate bool |
|
|
|
|
DefaultPrivate string |
|
|
|
|
MaxCreationLimit int |
|
|
|
|
MirrorQueueLength int |
|
|
|
|
PullRequestQueueLength int |
|
|
|
|
PreferredLicenses []string |
|
|
|
|
DisableHTTPGit bool |
|
|
|
|
AccessControlAllowOrigin string |
|
|
|
|
UseCompatSSHURI bool |
|
|
|
|
DefaultCloseIssuesViaCommitsInAnyBranch bool |
|
|
|
|
|
|
|
|
|
// Repository editor settings
|
|
|
|
|
Editor struct { |
|
|
|
|
LineWrapExtensions []string |
|
|
|
|
PreviewableFileModes []string |
|
|
|
|
} `ini:"-"` |
|
|
|
|
|
|
|
|
|
// Repository upload settings
|
|
|
|
|
Upload struct { |
|
|
|
|
Enabled bool |
|
|
|
|
TempPath string |
|
|
|
|
AllowedTypes []string `delim:"|"` |
|
|
|
|
FileMaxSize int64 |
|
|
|
|
MaxFiles int |
|
|
|
|
} `ini:"-"` |
|
|
|
|
|
|
|
|
|
// Repository local settings
|
|
|
|
|
Local struct { |
|
|
|
|
LocalCopyPath string |
|
|
|
|
LocalWikiPath string |
|
|
|
|
} `ini:"-"` |
|
|
|
|
|
|
|
|
|
// Pull request settings
|
|
|
|
|
PullRequest struct { |
|
|
|
|
WorkInProgressPrefixes []string |
|
|
|
|
} `ini:"repository.pull-request"` |
|
|
|
|
|
|
|
|
|
// Issue Setting
|
|
|
|
|
Issue struct { |
|
|
|
|
LockReasons []string |
|
|
|
|
} `ini:"repository.issue"` |
|
|
|
|
}{ |
|
|
|
|
AnsiCharset: "", |
|
|
|
|
ForcePrivate: false, |
|
|
|
|
DefaultPrivate: RepoCreatingLastUserVisibility, |
|
|
|
|
MaxCreationLimit: -1, |
|
|
|
|
MirrorQueueLength: 1000, |
|
|
|
|
PullRequestQueueLength: 1000, |
|
|
|
|
PreferredLicenses: []string{"Apache License 2.0,MIT License"}, |
|
|
|
|
DisableHTTPGit: false, |
|
|
|
|
AccessControlAllowOrigin: "", |
|
|
|
|
UseCompatSSHURI: false, |
|
|
|
|
DefaultCloseIssuesViaCommitsInAnyBranch: false, |
|
|
|
|
|
|
|
|
|
// Repository editor settings
|
|
|
|
|
Editor: struct { |
|
|
|
|
LineWrapExtensions []string |
|
|
|
|
PreviewableFileModes []string |
|
|
|
|
}{ |
|
|
|
|
LineWrapExtensions: strings.Split(".txt,.md,.markdown,.mdown,.mkd,", ","), |
|
|
|
|
PreviewableFileModes: []string{"markdown"}, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Repository upload settings
|
|
|
|
|
Upload: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
TempPath string |
|
|
|
|
AllowedTypes []string `delim:"|"` |
|
|
|
|
FileMaxSize int64 |
|
|
|
|
MaxFiles int |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
TempPath: "data/tmp/uploads", |
|
|
|
|
AllowedTypes: []string{}, |
|
|
|
|
FileMaxSize: 3, |
|
|
|
|
MaxFiles: 5, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Repository local settings
|
|
|
|
|
Local: struct { |
|
|
|
|
LocalCopyPath string |
|
|
|
|
LocalWikiPath string |
|
|
|
|
}{ |
|
|
|
|
LocalCopyPath: "tmp/local-repo", |
|
|
|
|
LocalWikiPath: "tmp/local-wiki", |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Pull request settings
|
|
|
|
|
PullRequest: struct { |
|
|
|
|
WorkInProgressPrefixes []string |
|
|
|
|
}{ |
|
|
|
|
WorkInProgressPrefixes: []string{"WIP:", "[WIP]"}, |
|
|
|
|
}, |
|
|
|
|
|
|
|
|
|
// Issue settings
|
|
|
|
|
Issue: struct { |
|
|
|
|
LockReasons []string |
|
|
|
|
}{ |
|
|
|
|
LockReasons: strings.Split("Too heated,Off-topic,Spam,Resolved", ","), |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
RepoRootPath string |
|
|
|
|
ScriptType = "bash" |
|
|
|
|
|
|
|
|
|
// UI settings
|
|
|
|
|
UI = struct { |
|
|
|
|
ExplorePagingNum int |
|
|
|
@ -400,149 +276,6 @@ var (
|
|
|
|
|
|
|
|
|
|
CSRFCookieName = "_csrf" |
|
|
|
|
|
|
|
|
|
// Cron tasks
|
|
|
|
|
Cron = struct { |
|
|
|
|
UpdateMirror struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
} `ini:"cron.update_mirrors"` |
|
|
|
|
RepoHealthCheck struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
Timeout time.Duration |
|
|
|
|
Args []string `delim:" "` |
|
|
|
|
} `ini:"cron.repo_health_check"` |
|
|
|
|
CheckRepoStats struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
} `ini:"cron.check_repo_stats"` |
|
|
|
|
ArchiveCleanup struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
OlderThan time.Duration |
|
|
|
|
} `ini:"cron.archive_cleanup"` |
|
|
|
|
SyncExternalUsers struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
UpdateExisting bool |
|
|
|
|
} `ini:"cron.sync_external_users"` |
|
|
|
|
DeletedBranchesCleanup struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
OlderThan time.Duration |
|
|
|
|
} `ini:"cron.deleted_branches_cleanup"` |
|
|
|
|
}{ |
|
|
|
|
UpdateMirror: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: false, |
|
|
|
|
Schedule: "@every 10m", |
|
|
|
|
}, |
|
|
|
|
RepoHealthCheck: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
Timeout time.Duration |
|
|
|
|
Args []string `delim:" "` |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: false, |
|
|
|
|
Schedule: "@every 24h", |
|
|
|
|
Timeout: 60 * time.Second, |
|
|
|
|
Args: []string{}, |
|
|
|
|
}, |
|
|
|
|
CheckRepoStats: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: true, |
|
|
|
|
Schedule: "@every 24h", |
|
|
|
|
}, |
|
|
|
|
ArchiveCleanup: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
OlderThan time.Duration |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: true, |
|
|
|
|
Schedule: "@every 24h", |
|
|
|
|
OlderThan: 24 * time.Hour, |
|
|
|
|
}, |
|
|
|
|
SyncExternalUsers: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
UpdateExisting bool |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: false, |
|
|
|
|
Schedule: "@every 24h", |
|
|
|
|
UpdateExisting: true, |
|
|
|
|
}, |
|
|
|
|
DeletedBranchesCleanup: struct { |
|
|
|
|
Enabled bool |
|
|
|
|
RunAtStart bool |
|
|
|
|
Schedule string |
|
|
|
|
OlderThan time.Duration |
|
|
|
|
}{ |
|
|
|
|
Enabled: true, |
|
|
|
|
RunAtStart: true, |
|
|
|
|
Schedule: "@every 24h", |
|
|
|
|
OlderThan: 24 * time.Hour, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Git settings
|
|
|
|
|
Git = struct { |
|
|
|
|
Version string `ini:"-"` |
|
|
|
|
DisableDiffHighlight bool |
|
|
|
|
MaxGitDiffLines int |
|
|
|
|
MaxGitDiffLineCharacters int |
|
|
|
|
MaxGitDiffFiles int |
|
|
|
|
GCArgs []string `delim:" "` |
|
|
|
|
Timeout struct { |
|
|
|
|
Default int |
|
|
|
|
Migrate int |
|
|
|
|
Mirror int |
|
|
|
|
Clone int |
|
|
|
|
Pull int |
|
|
|
|
GC int `ini:"GC"` |
|
|
|
|
} `ini:"git.timeout"` |
|
|
|
|
}{ |
|
|
|
|
DisableDiffHighlight: false, |
|
|
|
|
MaxGitDiffLines: 1000, |
|
|
|
|
MaxGitDiffLineCharacters: 5000, |
|
|
|
|
MaxGitDiffFiles: 100, |
|
|
|
|
GCArgs: []string{}, |
|
|
|
|
Timeout: struct { |
|
|
|
|
Default int |
|
|
|
|
Migrate int |
|
|
|
|
Mirror int |
|
|
|
|
Clone int |
|
|
|
|
Pull int |
|
|
|
|
GC int `ini:"GC"` |
|
|
|
|
}{ |
|
|
|
|
Default: int(git.DefaultCommandExecutionTimeout / time.Second), |
|
|
|
|
Migrate: 600, |
|
|
|
|
Mirror: 300, |
|
|
|
|
Clone: 300, |
|
|
|
|
Pull: 300, |
|
|
|
|
GC: 60, |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Mirror settings
|
|
|
|
|
Mirror struct { |
|
|
|
|
DefaultInterval time.Duration |
|
|
|
@ -612,7 +345,6 @@ var (
|
|
|
|
|
InternalToken string // internal access token
|
|
|
|
|
IterateBufferSize int |
|
|
|
|
|
|
|
|
|
ExternalMarkupParsers []MarkupParser |
|
|
|
|
// UILocation is the location on the UI, so that we can display the time on UI.
|
|
|
|
|
// Currently only show the default time.Local, it could be added to app.ini after UI is ready
|
|
|
|
|
UILocation = time.Local |
|
|
|
@ -1064,34 +796,7 @@ func NewContext() {
|
|
|
|
|
|
|
|
|
|
SSH.BuiltinServerUser = Cfg.Section("server").Key("BUILTIN_SSH_SERVER_USER").MustString(RunUser) |
|
|
|
|
|
|
|
|
|
// Determine and create root git repository path.
|
|
|
|
|
sec = Cfg.Section("repository") |
|
|
|
|
Repository.DisableHTTPGit = sec.Key("DISABLE_HTTP_GIT").MustBool() |
|
|
|
|
Repository.UseCompatSSHURI = sec.Key("USE_COMPAT_SSH_URI").MustBool() |
|
|
|
|
Repository.MaxCreationLimit = sec.Key("MAX_CREATION_LIMIT").MustInt(-1) |
|
|
|
|
RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gitea-repositories")) |
|
|
|
|
forcePathSeparator(RepoRootPath) |
|
|
|
|
if !filepath.IsAbs(RepoRootPath) { |
|
|
|
|
RepoRootPath = filepath.Join(AppWorkPath, RepoRootPath) |
|
|
|
|
} else { |
|
|
|
|
RepoRootPath = filepath.Clean(RepoRootPath) |
|
|
|
|
} |
|
|
|
|
ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") |
|
|
|
|
if err = Cfg.Section("repository").MapTo(&Repository); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Repository settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Repository.Editor settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Repository.Upload settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("repository.local").MapTo(&Repository.Local); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Repository.Local settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("repository.pull-request").MapTo(&Repository.PullRequest); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Repository.PullRequest settings: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if !filepath.IsAbs(Repository.Upload.TempPath) { |
|
|
|
|
Repository.Upload.TempPath = path.Join(AppWorkPath, Repository.Upload.TempPath) |
|
|
|
|
} |
|
|
|
|
newRepository() |
|
|
|
|
|
|
|
|
|
sec = Cfg.Section("picture") |
|
|
|
|
AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars")) |
|
|
|
@ -1145,17 +850,14 @@ func NewContext() {
|
|
|
|
|
log.Fatal(4, "Failed to map Markdown settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("admin").MapTo(&Admin); err != nil { |
|
|
|
|
log.Fatal(4, "Fail to map Admin settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("cron").MapTo(&Cron); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Cron settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("git").MapTo(&Git); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Git settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("api").MapTo(&API); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map API settings: %v", err) |
|
|
|
|
} else if err = Cfg.Section("metrics").MapTo(&Metrics); err != nil { |
|
|
|
|
log.Fatal(4, "Failed to map Metrics settings: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
git.DefaultCommandExecutionTimeout = time.Duration(Git.Timeout.Default) * time.Second |
|
|
|
|
newCron() |
|
|
|
|
newGit() |
|
|
|
|
|
|
|
|
|
sec = Cfg.Section("mirror") |
|
|
|
|
Mirror.MinInterval = sec.Key("MIN_INTERVAL").MustDuration(10 * time.Minute) |
|
|
|
@ -1193,57 +895,11 @@ func NewContext() {
|
|
|
|
|
|
|
|
|
|
HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt")) |
|
|
|
|
|
|
|
|
|
extensionReg := regexp.MustCompile(`\.\w`) |
|
|
|
|
for _, sec := range Cfg.Section("markup").ChildSections() { |
|
|
|
|
name := strings.TrimPrefix(sec.Name(), "markup.") |
|
|
|
|
if name == "" { |
|
|
|
|
log.Warn("name is empty, markup " + sec.Name() + "ignored") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
extensions := sec.Key("FILE_EXTENSIONS").Strings(",") |
|
|
|
|
var exts = make([]string, 0, len(extensions)) |
|
|
|
|
for _, extension := range extensions { |
|
|
|
|
if !extensionReg.MatchString(extension) { |
|
|
|
|
log.Warn(sec.Name() + " file extension " + extension + " is invalid. Extension ignored") |
|
|
|
|
} else { |
|
|
|
|
exts = append(exts, extension) |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if len(exts) == 0 { |
|
|
|
|
log.Warn(sec.Name() + " file extension is empty, markup " + name + " ignored") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
command := sec.Key("RENDER_COMMAND").MustString("") |
|
|
|
|
if command == "" { |
|
|
|
|
log.Warn(" RENDER_COMMAND is empty, markup " + name + " ignored") |
|
|
|
|
continue |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ExternalMarkupParsers = append(ExternalMarkupParsers, MarkupParser{ |
|
|
|
|
Enabled: sec.Key("ENABLED").MustBool(false), |
|
|
|
|
MarkupName: name, |
|
|
|
|
FileExtensions: exts, |
|
|
|
|
Command: command, |
|
|
|
|
IsInputFile: sec.Key("IS_INPUT_FILE").MustBool(false), |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
newMarkup() |
|
|
|
|
|
|
|
|
|
sec = Cfg.Section("U2F") |
|
|
|
|
U2F.TrustedFacets, _ = shellquote.Split(sec.Key("TRUSTED_FACETS").MustString(strings.TrimRight(AppURL, "/"))) |
|
|
|
|
U2F.AppID = sec.Key("APP_ID").MustString(strings.TrimRight(AppURL, "/")) |
|
|
|
|
|
|
|
|
|
binVersion, err := git.BinVersion() |
|
|
|
|
if err != nil { |
|
|
|
|
log.Fatal(4, "Error retrieving git version: %v", err) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if version.Compare(binVersion, "2.9", ">=") { |
|
|
|
|
// Explicitly disable credential helper, otherwise Git credentials might leak
|
|
|
|
|
git.GlobalCommandArgs = append(git.GlobalCommandArgs, "-c", "credential.helper=") |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func loadInternalToken(sec *ini.Section) string { |
|
|
|
|