func (this *service) ServeHTTP(w http.ResponseWriter, r *http.Request) { urlPath := r.URL.Path hash := urlPath[strings.LastIndex(urlPath, "/")+1:] size := this.mustInt(r, 80, "s", "size") // default size = 80*80 avatar := New(hash, this.cacheDir) avatar.AlterImage = this.altImage if avatar.Expired() { if err := avatar.UpdateTimeout(time.Millisecond * 1000); err != nil { log.Trace("avatar update error: %v", err) return } } if modtime, err := avatar.Modtime(); err == nil { etag := fmt.Sprintf("size(%d)", size) if t, err := time.Parse(http.TimeFormat, r.Header.Get("If-Modified-Since")); err == nil && modtime.Before(t.Add(1*time.Second)) && etag == r.Header.Get("If-None-Match") { h := w.Header() delete(h, "Content-Type") delete(h, "Content-Length") w.WriteHeader(http.StatusNotModified) return } w.Header().Set("Last-Modified", modtime.UTC().Format(http.TimeFormat)) w.Header().Set("ETag", etag) } w.Header().Set("Content-Type", "image/jpeg") if err := avatar.Encode(w, size); err != nil { log.Warn("avatar encode error: %v", err) w.WriteHeader(500) } }
// GitFsck calls 'git fsck' to check repository health. func GitFsck() { if isGitFscking { return } isGitFscking = true defer func() { isGitFscking = false }() args := append([]string{"fsck"}, setting.Git.Fsck.Args...) if err := x.Where("id > 0").Iterate(new(Repository), func(idx int, bean interface{}) error { repo := bean.(*Repository) if err := repo.GetOwner(); err != nil { return err } repoPath := RepoPath(repo.Owner.Name, repo.Name) _, _, err := process.ExecDir(-1, repoPath, "Repository health check", "git", args...) if err != nil { desc := fmt.Sprintf("Fail to health check repository(%s)", repoPath) log.Warn(desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "Fail to add notice: %v", err) } } return nil }); err != nil { log.Error(4, "repo.Fsck: %v", err) } }
func newNotifyMailService() { if !Cfg.Section("service").Key("ENABLE_NOTIFY_MAIL").MustBool() { return } else if MailService == nil { log.Warn("Notify Mail Service: Mail Service is not enabled") return } Service.EnableNotifyMail = true log.Info("Notify Mail Service Enabled") }
func newRegisterMailService() { if !Cfg.Section("service").Key("REGISTER_EMAIL_CONFIRM").MustBool() { return } else if MailService == nil { log.Warn("Register Mail Service: Mail Service is not enabled") return } Service.RegisterEmailConfirm = true log.Info("Register Mail Service Enabled") }
// UserSignIn validates user name and password. func UserSignIn(username, passowrd string) (*User, error) { var user *User if strings.Contains(username, "@") { user = &User{Email: strings.ToLower(username)} } else { user = &User{LowerName: strings.ToLower(username)} } hasUser, err := x.Get(user) if err != nil { return nil, err } if hasUser { switch user.LoginType { case LOGIN_NOTYPE, LOGIN_PLAIN: if user.ValidatePassword(passowrd) { return user, nil } return nil, ErrUserNotExist{user.ID, user.Name} default: var source LoginSource hasSource, err := x.Id(user.LoginSource).Get(&source) if err != nil { return nil, err } else if !hasSource { return nil, ErrLoginSourceNotExist{user.LoginSource} } return ExternalUserLogin(user, user.LoginName, passowrd, &source, false) } } sources := make([]*LoginSource, 0, 3) if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true}); err != nil { return nil, err } for _, source := range sources { authUser, err := ExternalUserLogin(nil, username, passowrd, source, true) if err == nil { return authUser, nil } log.Warn("Failed to login '%s' via '%s': %v", username, source.Name, err) } return nil, ErrUserNotExist{user.ID, user.Name} }
func listen(config *ssh.ServerConfig, port int) { listener, err := net.Listen("tcp", "0.0.0.0:"+com.ToStr(port)) if err != nil { panic(err) } for { // Once a ServerConfig has been configured, connections can be accepted. conn, err := listener.Accept() if err != nil { log.Error(3, "SSH: Error accepting incoming connection: %v", err) continue } // Before use, a handshake must be performed on the incoming net.Conn. // It must be handled in a separate goroutine, // otherwise one user could easily block entire loop. // For example, user could be asked to trust server key fingerprint and hangs. go func() { log.Trace("SSH: Handshaking for %s", conn.RemoteAddr()) sConn, chans, reqs, err := ssh.NewServerConn(conn, config) if err != nil { if err == io.EOF { log.Warn("SSH: Handshaking was terminated: %v", err) } else { log.Error(3, "SSH: Error on handshaking: %v", err) } return } log.Trace("SSH: Connection from %s (%s)", sConn.RemoteAddr(), sConn.ClientVersion()) // The incoming Request channel must be serviced. go ssh.DiscardRequests(reqs) go handleServerConn(sConn.Permissions.Extensions["key-id"], chans) }() } }
func UpdateLabel(ctx *middleware.Context, form auth.CreateLabelForm) { id := com.StrTo(ctx.Query("id")).MustInt64() if id == 0 { ctx.Error(404) return } l, err := models.GetLabelById(id) if l == nil { log.Warn("Could not find label id in db: %s", err) ctx.Redirect(ctx.Repo.RepoLink + "/issues") return } l.Name = form.Title l.Color = form.Color if err := models.UpdateLabel(l); err != nil { ctx.Handle(500, "issue.UpdateLabel(UpdateLabel)", err) return } ctx.Redirect(ctx.Repo.RepoLink + "/issues") }
func ParsePatch(pid int64, maxlines int, cmd *exec.Cmd, reader io.Reader) (*Diff, error) { scanner := bufio.NewScanner(reader) var ( curFile *DiffFile curSection = &DiffSection{ Lines: make([]*DiffLine, 0, 10), } leftLine, rightLine int isTooLong bool // FIXME: use first 30 lines to detect file encoding. Should use cache in the future. buf bytes.Buffer ) diff := &Diff{Files: make([]*DiffFile, 0)} var i int for scanner.Scan() { line := scanner.Text() // fmt.Println(i, line) if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") { continue } if line == "" { continue } i = i + 1 // FIXME: use first 30 lines to detect file encoding. if i <= 30 { buf.WriteString(line) } // Diff data too large, we only show the first about maxlines lines if i == maxlines { isTooLong = true log.Warn("Diff data too large") //return &Diff{}, nil } switch { case line[0] == ' ': diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine} leftLine++ rightLine++ curSection.Lines = append(curSection.Lines, diffLine) continue case line[0] == '@': if isTooLong { return diff, nil } curSection = &DiffSection{} curFile.Sections = append(curFile.Sections, curSection) ss := strings.Split(line, "@@") diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line} curSection.Lines = append(curSection.Lines, diffLine) // Parse line number. ranges := strings.Split(ss[len(ss)-2][1:], " ") leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int() rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int() continue case line[0] == '+': curFile.Addition++ diff.TotalAddition++ diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine} rightLine++ curSection.Lines = append(curSection.Lines, diffLine) continue case line[0] == '-': curFile.Deletion++ diff.TotalDeletion++ diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine} if leftLine > 0 { leftLine++ } curSection.Lines = append(curSection.Lines, diffLine) case strings.HasPrefix(line, "Binary"): curFile.IsBin = true continue } // Get new file. if strings.HasPrefix(line, DIFF_HEAD) { if isTooLong { return diff, nil } fs := strings.Split(line[len(DIFF_HEAD):], " ") a := fs[0] curFile = &DiffFile{ Name: a[strings.Index(a, "/")+1:], Index: len(diff.Files) + 1, Type: DIFF_FILE_CHANGE, Sections: make([]*DiffSection, 0, 10), } diff.Files = append(diff.Files, curFile) // Check file diff type. for scanner.Scan() { switch { case strings.HasPrefix(scanner.Text(), "new file"): curFile.Type = DIFF_FILE_ADD curFile.IsDeleted = false curFile.IsCreated = true case strings.HasPrefix(scanner.Text(), "deleted"): curFile.Type = DIFF_FILE_DEL curFile.IsCreated = false curFile.IsDeleted = true case strings.HasPrefix(scanner.Text(), "index"): curFile.Type = DIFF_FILE_CHANGE curFile.IsCreated = false curFile.IsDeleted = false } if curFile.Type > 0 { break } } } } // FIXME: use first 30 lines to detect file encoding. charsetLabel, err := base.DetectEncoding(buf.Bytes()) if charsetLabel != "utf8" && err == nil { encoding, _ := charset.Lookup(charsetLabel) if encoding != nil { d := encoding.NewDecoder() for _, f := range diff.Files { for _, sec := range f.Sections { for _, l := range sec.Lines { if c, _, err := transform.String(d, l.Content); err == nil { l.Content = c } } } } } } return diff, nil }
func handleServerConn(keyID string, chans <-chan ssh.NewChannel) { for newChan := range chans { if newChan.ChannelType() != "session" { newChan.Reject(ssh.UnknownChannelType, "unknown channel type") continue } ch, reqs, err := newChan.Accept() if err != nil { log.Error(3, "Error accepting channel: %v", err) continue } go func(in <-chan *ssh.Request) { defer ch.Close() for req := range in { payload := cleanCommand(string(req.Payload)) switch req.Type { case "env": args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v") if len(args) != 2 { log.Warn("SSH: Invalid env arguments: '%#v'", args) continue } args[0] = strings.TrimLeft(args[0], "\x04") _, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1]) if err != nil { log.Error(3, "env: %v", err) return } case "exec": cmdName := strings.TrimLeft(payload, "'()") log.Trace("SSH: Payload: %v", cmdName) args := []string{"serv", "key-" + keyID, "--config=" + setting.CustomConf} log.Trace("SSH: Arguments: %v", args) cmd := exec.Command(setting.AppPath, args...) cmd.Env = append(os.Environ(), "SSH_ORIGINAL_COMMAND="+cmdName) stdout, err := cmd.StdoutPipe() if err != nil { log.Error(3, "SSH: StdoutPipe: %v", err) return } stderr, err := cmd.StderrPipe() if err != nil { log.Error(3, "SSH: StderrPipe: %v", err) return } input, err := cmd.StdinPipe() if err != nil { log.Error(3, "SSH: StdinPipe: %v", err) return } // FIXME: check timeout if err = cmd.Start(); err != nil { log.Error(3, "SSH: Start: %v", err) return } req.Reply(true, nil) go io.Copy(input, ch) io.Copy(ch, stdout) io.Copy(ch.Stderr(), stderr) if err = cmd.Wait(); err != nil { log.Error(3, "SSH: Wait: %v", err) return } ch.SendRequest("exit-status", false, []byte{0, 0, 0, 0}) return default: } } }(reqs) } }
// NewConfigContext initializes configuration context. // NOTE: do not print any log except error. func NewConfigContext() { workDir, err := WorkDir() if err != nil { log.Fatal(4, "Fail to get work directory: %v", err) } Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini")) if err != nil { log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err) } CustomPath = os.Getenv("GOGS_CUSTOM") if len(CustomPath) == 0 { CustomPath = path.Join(workDir, "custom") } if len(CustomConf) == 0 { CustomConf = path.Join(CustomPath, "conf/app.ini") } if com.IsFile(CustomConf) { if err = Cfg.Append(CustomConf); err != nil { log.Fatal(4, "Fail to load custom conf '%s': %v", CustomConf, err) } } else { log.Warn("Custom config (%s) not found, ignore this if you're running first time", CustomConf) } Cfg.NameMapper = ini.AllCapsUnderscore LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log")) forcePathSeparator(LogRootPath) sec := Cfg.Section("server") AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service") AppUrl = sec.Key("ROOT_URL").MustString("http://localhost:3000/") if AppUrl[len(AppUrl)-1] != '/' { AppUrl += "/" } // Check if has app suburl. url, err := url.Parse(AppUrl) if err != nil { log.Fatal(4, "Invalid ROOT_URL(%s): %s", AppUrl, err) } AppSubUrl = strings.TrimSuffix(url.Path, "/") Protocol = HTTP if sec.Key("PROTOCOL").String() == "https" { Protocol = HTTPS CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() } else if sec.Key("PROTOCOL").String() == "fcgi" { Protocol = FCGI } Domain = sec.Key("DOMAIN").MustString("localhost") HttpAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") HttpPort = sec.Key("HTTP_PORT").MustString("3000") DisableSSH = sec.Key("DISABLE_SSH").MustBool() SSHPort = sec.Key("SSH_PORT").MustInt(22) OfflineMode = sec.Key("OFFLINE_MODE").MustBool() DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir) EnableGzip = sec.Key("ENABLE_GZIP").MustBool() switch sec.Key("LANDING_PAGE").MustString("home") { case "explore": LandingPageUrl = LANDING_PAGE_EXPLORE default: LandingPageUrl = LANDING_PAGE_HOME } sec = Cfg.Section("security") InstallLock = sec.Key("INSTALL_LOCK").MustBool() SecretKey = sec.Key("SECRET_KEY").String() LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt() CookieUserName = sec.Key("COOKIE_USERNAME").String() CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String() ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") sec = Cfg.Section("attachment") AttachmentPath = sec.Key("PATH").MustString("data/attachments") if !filepath.IsAbs(AttachmentPath) { AttachmentPath = path.Join(workDir, AttachmentPath) } AttachmentAllowedTypes = sec.Key("ALLOWED_TYPES").MustString("image/jpeg|image/png") AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(32) AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(10) AttachmentEnabled = sec.Key("ENABLE").MustBool(true) TimeFormat = map[string]string{ "ANSIC": time.ANSIC, "UnixDate": time.UnixDate, "RubyDate": time.RubyDate, "RFC822": time.RFC822, "RFC822Z": time.RFC822Z, "RFC850": time.RFC850, "RFC1123": time.RFC1123, "RFC1123Z": time.RFC1123Z, "RFC3339": time.RFC3339, "RFC3339Nano": time.RFC3339Nano, "Kitchen": time.Kitchen, "Stamp": time.Stamp, "StampMilli": time.StampMilli, "StampMicro": time.StampMicro, "StampNano": time.StampNano, }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")] RunUser = Cfg.Section("").Key("RUN_USER").String() curUser := os.Getenv("USER") if len(curUser) == 0 { curUser = os.Getenv("USERNAME") } // Does not check run user when the install lock is off. if InstallLock && RunUser != curUser { log.Fatal(4, "Expect user(%s) but current user is: %s", RunUser, curUser) } // Determine and create root git repository path. homeDir, err := com.HomeDir() if err != nil { log.Fatal(4, "Fail to get home directory: %v", err) } homeDir = strings.Replace(homeDir, "\\", "/", -1) sec = Cfg.Section("repository") RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories")) forcePathSeparator(RepoRootPath) if !filepath.IsAbs(RepoRootPath) { RepoRootPath = path.Join(workDir, RepoRootPath) } else { RepoRootPath = path.Clean(RepoRootPath) } ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") sec = Cfg.Section("picture") PictureService = sec.Key("SERVICE").In("server", []string{"server"}) AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString("data/avatars") forcePathSeparator(AvatarUploadPath) if !filepath.IsAbs(AvatarUploadPath) { AvatarUploadPath = path.Join(workDir, AvatarUploadPath) } switch sec.Key("GRAVATAR_SOURCE").MustString("gravatar") { case "duoshuo": GravatarSource = "http://gravatar.duoshuo.com/avatar/" default: GravatarSource = "//1.gravatar.com/avatar/" } DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool() if OfflineMode { DisableGravatar = true } if err = Cfg.Section("git").MapTo(&Git); err != nil { log.Fatal(4, "Fail to map Git settings: %v", err) } Langs = Cfg.Section("i18n").Key("LANGS").Strings(",") Names = Cfg.Section("i18n").Key("NAMES").Strings(",") ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool() HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt")) }
// NewContext initializes configuration context. // NOTE: do not print any log except error. func NewContext() { workDir, err := WorkDir() if err != nil { log.Fatal(4, "Fail to get work directory: %v", err) } Cfg, err = ini.Load(bindata.MustAsset("conf/app.ini")) if err != nil { log.Fatal(4, "Fail to parse 'conf/app.ini': %v", err) } CustomPath = os.Getenv("GOGS_CUSTOM") if len(CustomPath) == 0 { CustomPath = workDir + "/custom" } if len(CustomConf) == 0 { CustomConf = CustomPath + "/conf/app.ini" } if com.IsFile(CustomConf) { if err = Cfg.Append(CustomConf); err != nil { log.Fatal(4, "Fail to load custom conf '%s': %v", CustomConf, err) } } else { log.Warn("Custom config '%s' not found, ignore this if you're running first time", CustomConf) } Cfg.NameMapper = ini.AllCapsUnderscore homeDir, err := com.HomeDir() if err != nil { log.Fatal(4, "Fail to get home directory: %v", err) } homeDir = strings.Replace(homeDir, "\\", "/", -1) LogRootPath = Cfg.Section("log").Key("ROOT_PATH").MustString(path.Join(workDir, "log")) forcePathSeparator(LogRootPath) sec := Cfg.Section("server") AppName = Cfg.Section("").Key("APP_NAME").MustString("Gogs: Go Git Service") AppUrl = sec.Key("ROOT_URL").MustString("http://localhost:3000/") if AppUrl[len(AppUrl)-1] != '/' { AppUrl += "/" } // Check if has app suburl. url, err := url.Parse(AppUrl) if err != nil { log.Fatal(4, "Invalid ROOT_URL '%s': %s", AppUrl, err) } // Suburl should start with '/' and end without '/', such as '/{subpath}'. // This value is empty if site does not have sub-url. AppSubUrl = strings.TrimSuffix(url.Path, "/") AppSubUrlDepth = strings.Count(AppSubUrl, "/") Protocol = HTTP if sec.Key("PROTOCOL").String() == "https" { Protocol = HTTPS CertFile = sec.Key("CERT_FILE").String() KeyFile = sec.Key("KEY_FILE").String() } else if sec.Key("PROTOCOL").String() == "fcgi" { Protocol = FCGI } else if sec.Key("PROTOCOL").String() == "unix" { Protocol = UNIX_SOCKET UnixSocketPermissionRaw := sec.Key("UNIX_SOCKET_PERMISSION").MustString("666") UnixSocketPermissionParsed, err := strconv.ParseUint(UnixSocketPermissionRaw, 8, 32) if err != nil || UnixSocketPermissionParsed > 0777 { log.Fatal(4, "Fail to parse unixSocketPermission: %s", UnixSocketPermissionRaw) } UnixSocketPermission = uint32(UnixSocketPermissionParsed) } Domain = sec.Key("DOMAIN").MustString("localhost") HTTPAddr = sec.Key("HTTP_ADDR").MustString("0.0.0.0") HTTPPort = sec.Key("HTTP_PORT").MustString("3000") LocalURL = sec.Key("LOCAL_ROOT_URL").MustString(string(Protocol) + "://localhost:" + HTTPPort + "/") OfflineMode = sec.Key("OFFLINE_MODE").MustBool() DisableRouterLog = sec.Key("DISABLE_ROUTER_LOG").MustBool() StaticRootPath = sec.Key("STATIC_ROOT_PATH").MustString(workDir) AppDataPath = sec.Key("APP_DATA_PATH").MustString("data") EnableGzip = sec.Key("ENABLE_GZIP").MustBool() switch sec.Key("LANDING_PAGE").MustString("home") { case "explore": LandingPageURL = LANDING_PAGE_EXPLORE default: LandingPageURL = LANDING_PAGE_HOME } SSH.RootPath = path.Join(homeDir, ".ssh") SSH.KeyTestPath = os.TempDir() if err = Cfg.Section("server").MapTo(&SSH); err != nil { log.Fatal(4, "Fail to map SSH settings: %v", err) } // When disable SSH, start builtin server value is ignored. if SSH.Disabled { SSH.StartBuiltinServer = false } if !SSH.Disabled && !SSH.StartBuiltinServer { if err := os.MkdirAll(SSH.RootPath, 0700); err != nil { log.Fatal(4, "Fail to create '%s': %v", SSH.RootPath, err) } else if err = os.MkdirAll(SSH.KeyTestPath, 0644); err != nil { log.Fatal(4, "Fail to create '%s': %v", SSH.KeyTestPath, err) } } SSH.MinimumKeySizeCheck = sec.Key("MINIMUM_KEY_SIZE_CHECK").MustBool() SSH.MinimumKeySizes = map[string]int{} minimumKeySizes := Cfg.Section("ssh.minimum_key_sizes").Keys() for _, key := range minimumKeySizes { if key.MustInt() != -1 { SSH.MinimumKeySizes[strings.ToLower(key.Name())] = key.MustInt() } } sec = Cfg.Section("security") InstallLock = sec.Key("INSTALL_LOCK").MustBool() SecretKey = sec.Key("SECRET_KEY").String() LogInRememberDays = sec.Key("LOGIN_REMEMBER_DAYS").MustInt() CookieUserName = sec.Key("COOKIE_USERNAME").String() CookieRememberName = sec.Key("COOKIE_REMEMBER_NAME").String() ReverseProxyAuthUser = sec.Key("REVERSE_PROXY_AUTHENTICATION_USER").MustString("X-WEBAUTH-USER") sec = Cfg.Section("attachment") AttachmentPath = sec.Key("PATH").MustString(path.Join(AppDataPath, "attachments")) if !filepath.IsAbs(AttachmentPath) { AttachmentPath = path.Join(workDir, AttachmentPath) } AttachmentAllowedTypes = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1) AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(4) AttachmentMaxFiles = sec.Key("MAX_FILES").MustInt(5) AttachmentEnabled = sec.Key("ENABLE").MustBool(true) TimeFormat = map[string]string{ "ANSIC": time.ANSIC, "UnixDate": time.UnixDate, "RubyDate": time.RubyDate, "RFC822": time.RFC822, "RFC822Z": time.RFC822Z, "RFC850": time.RFC850, "RFC1123": time.RFC1123, "RFC1123Z": time.RFC1123Z, "RFC3339": time.RFC3339, "RFC3339Nano": time.RFC3339Nano, "Kitchen": time.Kitchen, "Stamp": time.Stamp, "StampMilli": time.StampMilli, "StampMicro": time.StampMicro, "StampNano": time.StampNano, }[Cfg.Section("time").Key("FORMAT").MustString("RFC1123")] RunUser = Cfg.Section("").Key("RUN_USER").String() // Does not check run user when the install lock is off. if InstallLock { currentUser, match := IsRunUserMatchCurrentUser(RunUser) if !match { log.Fatal(4, "Expect user '%s' but current user is: %s", RunUser, currentUser) } } // Determine and create root git repository path. sec = Cfg.Section("repository") RepoRootPath = sec.Key("ROOT").MustString(path.Join(homeDir, "gogs-repositories")) forcePathSeparator(RepoRootPath) if !filepath.IsAbs(RepoRootPath) { RepoRootPath = path.Join(workDir, RepoRootPath) } else { RepoRootPath = path.Clean(RepoRootPath) } ScriptType = sec.Key("SCRIPT_TYPE").MustString("bash") if err = Cfg.Section("repository").MapTo(&Repository); err != nil { log.Fatal(4, "Fail to map Repository settings: %v", err) } else if err = Cfg.Section("repository.editor").MapTo(&Repository.Editor); err != nil { log.Fatal(4, "Fail to map Repository.Editor settings: %v", err) } else if err = Cfg.Section("repository.upload").MapTo(&Repository.Upload); err != nil { log.Fatal(4, "Fail to map Repository.Upload settings: %v", err) } if !filepath.IsAbs(Repository.Upload.TempPath) { Repository.Upload.TempPath = path.Join(workDir, Repository.Upload.TempPath) } sec = Cfg.Section("picture") AvatarUploadPath = sec.Key("AVATAR_UPLOAD_PATH").MustString(path.Join(AppDataPath, "avatars")) forcePathSeparator(AvatarUploadPath) if !filepath.IsAbs(AvatarUploadPath) { AvatarUploadPath = path.Join(workDir, AvatarUploadPath) } switch source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source { case "duoshuo": GravatarSource = "http://gravatar.duoshuo.com/avatar/" case "gravatar": GravatarSource = "https://secure.gravatar.com/avatar/" default: GravatarSource = source } DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool() EnableFederatedAvatar = sec.Key("ENABLE_FEDERATED_AVATAR").MustBool() if OfflineMode { DisableGravatar = true EnableFederatedAvatar = false } if DisableGravatar { EnableFederatedAvatar = false } if EnableFederatedAvatar { LibravatarService = libravatar.New() parts := strings.Split(GravatarSource, "/") if len(parts) >= 3 { if parts[0] == "https:" { LibravatarService.SetUseHTTPS(true) LibravatarService.SetSecureFallbackHost(parts[2]) } else { LibravatarService.SetUseHTTPS(false) LibravatarService.SetFallbackHost(parts[2]) } } } if err = Cfg.Section("ui").MapTo(&UI); err != nil { log.Fatal(4, "Fail to map UI settings: %v", err) } else if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil { log.Fatal(4, "Fail to map Markdown settings: %v", err) } else if err = Cfg.Section("cron").MapTo(&Cron); err != nil { log.Fatal(4, "Fail to map Cron settings: %v", err) } else if err = Cfg.Section("git").MapTo(&Git); err != nil { log.Fatal(4, "Fail to map Git settings: %v", err) } else if err = Cfg.Section("mirror").MapTo(&Mirror); err != nil { log.Fatal(4, "Fail to map Mirror settings: %v", err) } else if err = Cfg.Section("api").MapTo(&API); err != nil { log.Fatal(4, "Fail to map API settings: %v", err) } if Mirror.DefaultInterval <= 0 { Mirror.DefaultInterval = 24 } Langs = Cfg.Section("i18n").Key("LANGS").Strings(",") Names = Cfg.Section("i18n").Key("NAMES").Strings(",") dateLangs = Cfg.Section("i18n.datelang").KeysHash() ShowFooterBranding = Cfg.Section("other").Key("SHOW_FOOTER_BRANDING").MustBool() ShowFooterVersion = Cfg.Section("other").Key("SHOW_FOOTER_VERSION").MustBool() ShowFooterTemplateLoadTime = Cfg.Section("other").Key("SHOW_FOOTER_TEMPLATE_LOAD_TIME").MustBool() HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt")) }
// DeleteRepository deletes a repository for a user or organization. func DeleteRepository(uid, repoID int64, userName string) error { repo := &Repository{Id: repoID, OwnerId: uid} has, err := x.Get(repo) if err != nil { return err } else if !has { return ErrRepoNotExist{repoID, uid, ""} } // In case is a organization. org, err := GetUserById(uid) if err != nil { return err } if org.IsOrganization() { if err = org.GetTeams(); err != nil { return err } } sess := x.NewSession() defer sessionRelease(sess) if err = sess.Begin(); err != nil { return err } if org.IsOrganization() { for _, t := range org.Teams { if !t.hasRepository(sess, repoID) { continue } else if err = t.removeRepository(sess, repo, false); err != nil { return err } } } if _, err = sess.Delete(&Repository{Id: repoID}); err != nil { return err } else if _, err = sess.Delete(&Access{RepoID: repo.Id}); err != nil { return err } else if _, err = sess.Delete(&Action{RepoID: repo.Id}); err != nil { return err } else if _, err = sess.Delete(&Watch{RepoID: repoID}); err != nil { return err } else if _, err = sess.Delete(&Mirror{RepoId: repoID}); err != nil { return err } else if _, err = sess.Delete(&IssueUser{RepoId: repoID}); err != nil { return err } else if _, err = sess.Delete(&Milestone{RepoId: repoID}); err != nil { return err } else if _, err = sess.Delete(&Release{RepoId: repoID}); err != nil { return err } else if _, err = sess.Delete(&Collaboration{RepoID: repoID}); err != nil { return err } // Delete comments. issues := make([]*Issue, 0, 25) if err = sess.Where("repo_id=?", repoID).Find(&issues); err != nil { return err } for i := range issues { if _, err = sess.Delete(&Comment{IssueId: issues[i].Id}); err != nil { return err } } if _, err = sess.Delete(&Issue{RepoId: repoID}); err != nil { return err } if repo.IsFork { if _, err = sess.Exec("UPDATE `repository` SET num_forks=num_forks-1 WHERE id=?", repo.ForkId); err != nil { return err } } if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", uid); err != nil { return err } // Remove repository files. if err = os.RemoveAll(RepoPath(userName, repo.Name)); err != nil { desc := fmt.Sprintf("delete repository files(%s/%s): %v", userName, repo.Name, err) log.Warn(desc) if err = CreateRepositoryNotice(desc); err != nil { log.Error(4, "add notice: %v", err) } } return sess.Commit() }
func Issues(ctx *middleware.Context) { ctx.Data["Title"] = ctx.Tr("issues") ctx.Data["PageIsDashboard"] = true ctx.Data["PageIsIssues"] = true viewType := ctx.Query("type") types := []string{"assigned", "created_by"} if !com.IsSliceContainsStr(types, viewType) { viewType = "all" } isShowClosed := ctx.Query("state") == "closed" var filterMode int switch viewType { case "assigned": filterMode = models.FM_ASSIGN case "created_by": filterMode = models.FM_CREATE } repoId, _ := com.StrTo(ctx.Query("repoid")).Int64() issueStats := models.GetUserIssueStats(ctx.User.Id, filterMode) // Get all repositories. repos, err := models.GetRepositories(ctx.User.Id, true) if err != nil { ctx.Handle(500, "user.Issues(GetRepositories)", err) return } repoIds := make([]int64, 0, len(repos)) showRepos := make([]*models.Repository, 0, len(repos)) for _, repo := range repos { if repo.NumIssues == 0 { continue } repoIds = append(repoIds, repo.Id) repo.NumOpenIssues = repo.NumIssues - repo.NumClosedIssues issueStats.AllCount += int64(repo.NumOpenIssues) if isShowClosed { if repo.NumClosedIssues > 0 { if filterMode == models.FM_CREATE { repo.NumClosedIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed)) } showRepos = append(showRepos, repo) } } else { if repo.NumOpenIssues > 0 { if filterMode == models.FM_CREATE { repo.NumOpenIssues = int(models.GetIssueCountByPoster(ctx.User.Id, repo.Id, isShowClosed)) } showRepos = append(showRepos, repo) } } } if repoId > 0 { repoIds = []int64{repoId} } page, _ := com.StrTo(ctx.Query("page")).Int() // Get all issues. var ius []*models.IssueUser switch viewType { case "assigned": fallthrough case "created_by": ius, err = models.GetIssueUserPairsByMode(ctx.User.Id, repoId, isShowClosed, page, filterMode) default: ius, err = models.GetIssueUserPairsByRepoIds(repoIds, isShowClosed, page) } if err != nil { ctx.Handle(500, "user.Issues(GetAllIssueUserPairs)", err) return } issues := make([]*models.Issue, len(ius)) for i := range ius { issues[i], err = models.GetIssueById(ius[i].IssueId) if err != nil { if err == models.ErrIssueNotExist { log.Warn("user.Issues(GetIssueById #%d): issue not exist", ius[i].IssueId) continue } else { ctx.Handle(500, fmt.Sprintf("user.Issues(GetIssueById #%d)", ius[i].IssueId), err) return } } issues[i].Repo, err = models.GetRepositoryById(issues[i].RepoId) if err != nil { if models.IsErrRepoNotExist(err) { log.Warn("user.Issues(GetRepositoryById #%d): repository not exist", issues[i].RepoId) continue } else { ctx.Handle(500, fmt.Sprintf("user.Issues(GetRepositoryById #%d)", issues[i].RepoId), err) return } } if err = issues[i].Repo.GetOwner(); err != nil { ctx.Handle(500, "user.Issues(GetOwner)", err) return } if err = issues[i].GetPoster(); err != nil { ctx.Handle(500, "user.Issues(GetUserById)", err) return } } ctx.Data["RepoId"] = repoId ctx.Data["Repos"] = showRepos ctx.Data["Issues"] = issues ctx.Data["ViewType"] = viewType ctx.Data["IssueStats"] = issueStats ctx.Data["IsShowClosed"] = isShowClosed if isShowClosed { ctx.Data["State"] = "closed" ctx.Data["ShowCount"] = issueStats.ClosedCount } else { ctx.Data["ShowCount"] = issueStats.OpenCount } ctx.Data["ContextUser"] = ctx.User ctx.HTML(200, ISSUES) }
// UserSignIn validates user name and password. func UserSignIn(uname, passwd string) (*User, error) { u := new(User) if strings.Contains(uname, "@") { u = &User{Email: uname} } else { u = &User{LowerName: strings.ToLower(uname)} } has, err := x.Get(u) if err != nil { return nil, err } if u.LoginType == NOTYPE && has { u.LoginType = PLAIN } // For plain login, user must exist to reach this line. // Now verify password. if u.LoginType == PLAIN { if !u.ValidtePassword(passwd) { return nil, ErrUserNotExist } return u, nil } if !has { var sources []LoginSource if err = x.UseBool().Find(&sources, &LoginSource{IsActived: true, AllowAutoRegister: true}); err != nil { return nil, err } for _, source := range sources { if source.Type == LDAP { u, err := LoginUserLdapSource(nil, uname, passwd, source.Id, source.Cfg.(*LDAPConfig), true) if err == nil { return u, nil } log.Warn("Fail to login(%s) by LDAP(%s): %v", uname, source.Name, err) } else if source.Type == SMTP { u, err := LoginUserSMTPSource(nil, uname, passwd, source.Id, source.Cfg.(*SMTPConfig), true) if err == nil { return u, nil } log.Warn("Fail to login(%s) by SMTP(%s): %v", uname, source.Name, err) } } return nil, ErrUserNotExist } var source LoginSource hasSource, err := x.Id(u.LoginSource).Get(&source) if err != nil { return nil, err } else if !hasSource { return nil, ErrLoginSourceNotExist } else if !source.IsActived { return nil, ErrLoginSourceNotActived } switch u.LoginType { case LDAP: return LoginUserLdapSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*LDAPConfig), false) case SMTP: return LoginUserSMTPSource(u, u.LoginName, passwd, source.Id, source.Cfg.(*SMTPConfig), false) } return nil, ErrUnsupportedLoginType }
func ViewIssue(ctx *middleware.Context) { ctx.Data["AttachmentsEnabled"] = setting.AttachmentEnabled idx := com.StrTo(ctx.Params(":index")).MustInt64() if idx == 0 { ctx.Handle(404, "issue.ViewIssue", nil) return } issue, err := models.GetIssueByIndex(ctx.Repo.Repository.Id, idx) if err != nil { if err == models.ErrIssueNotExist { ctx.Handle(404, "issue.ViewIssue(GetIssueByIndex)", err) } else { ctx.Handle(500, "issue.ViewIssue(GetIssueByIndex)", err) } return } // Get labels. if err = issue.GetLabels(); err != nil { ctx.Handle(500, "issue.ViewIssue(GetLabels)", err) return } labels, err := models.GetLabels(ctx.Repo.Repository.Id) if err != nil { ctx.Handle(500, "issue.ViewIssue(GetLabels.2)", err) return } checkLabels(issue.Labels, labels) ctx.Data["Labels"] = labels // Get assigned milestone. if issue.MilestoneId > 0 { ctx.Data["Milestone"], err = models.GetMilestoneById(issue.MilestoneId) if err != nil { if err == models.ErrMilestoneNotExist { log.Warn("issue.ViewIssue(GetMilestoneById): %v", err) } else { ctx.Handle(500, "issue.ViewIssue(GetMilestoneById)", err) return } } } // Get all milestones. ctx.Data["OpenMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, false) if err != nil { ctx.Handle(500, "issue.ViewIssue(GetMilestones.1): %v", err) return } ctx.Data["ClosedMilestones"], err = models.GetMilestones(ctx.Repo.Repository.Id, true) if err != nil { ctx.Handle(500, "issue.ViewIssue(GetMilestones.2): %v", err) return } // Get all collaborators. ctx.Data["Collaborators"], err = ctx.Repo.Repository.GetCollaborators() if err != nil { ctx.Handle(500, "issue.CreateIssue(GetCollaborators)", err) return } if ctx.IsSigned { // Update issue-user. if err = models.UpdateIssueUserPairByRead(ctx.User.Id, issue.Id); err != nil { ctx.Handle(500, "issue.ViewIssue(UpdateIssueUserPairByRead): %v", err) return } } // Get poster and Assignee. if err = issue.GetPoster(); err != nil { ctx.Handle(500, "issue.ViewIssue(GetPoster): %v", err) return } else if err = issue.GetAssignee(); err != nil { ctx.Handle(500, "issue.ViewIssue(GetAssignee): %v", err) return } issue.RenderedContent = string(base.RenderMarkdown([]byte(issue.Content), ctx.Repo.RepoLink)) // Get comments. comments, err := models.GetIssueComments(issue.Id) if err != nil { ctx.Handle(500, "issue.ViewIssue(GetIssueComments): %v", err) return } // Get posters. for i := range comments { u, err := models.GetUserById(comments[i].PosterId) if err != nil { ctx.Handle(500, "issue.ViewIssue(GetUserById.2): %v", err) return } comments[i].Poster = u if comments[i].Type == models.COMMENT_TYPE_COMMENT { comments[i].Content = string(base.RenderMarkdown([]byte(comments[i].Content), ctx.Repo.RepoLink)) } } ctx.Data["AllowedTypes"] = setting.AttachmentAllowedTypes ctx.Data["Title"] = issue.Name ctx.Data["Issue"] = issue ctx.Data["Comments"] = comments ctx.Data["IsIssueOwner"] = ctx.Repo.IsOwner() || (ctx.IsSigned && issue.PosterId == ctx.User.Id) ctx.Data["IsRepoToolbarIssues"] = true ctx.Data["IsRepoToolbarIssuesList"] = false ctx.HTML(200, ISSUE_VIEW) }
// TODO: move this function to gogits/git-module func ParsePatch(maxLines, maxLineCharacteres, maxFiles int, reader io.Reader) (*Diff, error) { var ( diff = &Diff{Files: make([]*DiffFile, 0)} curFile *DiffFile curSection = &DiffSection{ Lines: make([]*DiffLine, 0, 10), } leftLine, rightLine int lineCount int curFileLinesCount int ) input := bufio.NewReader(reader) isEOF := false for !isEOF { line, err := input.ReadString('\n') if err != nil { if err == io.EOF { isEOF = true } else { return nil, fmt.Errorf("ReadString: %v", err) } } if len(line) > 0 && line[len(line)-1] == '\n' { // Remove line break. line = line[:len(line)-1] } if strings.HasPrefix(line, "+++ ") || strings.HasPrefix(line, "--- ") || len(line) == 0 { continue } curFileLinesCount++ lineCount++ // Diff data too large, we only show the first about maxlines lines if curFileLinesCount >= maxLines || len(line) >= maxLineCharacteres { curFile.IsIncomplete = true } switch { case line[0] == ' ': diffLine := &DiffLine{Type: DIFF_LINE_PLAIN, Content: line, LeftIdx: leftLine, RightIdx: rightLine} leftLine++ rightLine++ curSection.Lines = append(curSection.Lines, diffLine) continue case line[0] == '@': curSection = &DiffSection{} curFile.Sections = append(curFile.Sections, curSection) ss := strings.Split(line, "@@") diffLine := &DiffLine{Type: DIFF_LINE_SECTION, Content: line} curSection.Lines = append(curSection.Lines, diffLine) // Parse line number. ranges := strings.Split(ss[1][1:], " ") leftLine, _ = com.StrTo(strings.Split(ranges[0], ",")[0][1:]).Int() if len(ranges) > 1 { rightLine, _ = com.StrTo(strings.Split(ranges[1], ",")[0]).Int() } else { log.Warn("Parse line number failed: %v", line) rightLine = leftLine } continue case line[0] == '+': curFile.Addition++ diff.TotalAddition++ diffLine := &DiffLine{Type: DIFF_LINE_ADD, Content: line, RightIdx: rightLine} rightLine++ curSection.Lines = append(curSection.Lines, diffLine) continue case line[0] == '-': curFile.Deletion++ diff.TotalDeletion++ diffLine := &DiffLine{Type: DIFF_LINE_DEL, Content: line, LeftIdx: leftLine} if leftLine > 0 { leftLine++ } curSection.Lines = append(curSection.Lines, diffLine) case strings.HasPrefix(line, "Binary"): curFile.IsBin = true continue } // Get new file. if strings.HasPrefix(line, DIFF_HEAD) { middle := -1 // Note: In case file name is surrounded by double quotes (it happens only in git-shell). // e.g. diff --git "a/xxx" "b/xxx" hasQuote := line[len(DIFF_HEAD)] == '"' if hasQuote { middle = strings.Index(line, ` "b/`) } else { middle = strings.Index(line, " b/") } beg := len(DIFF_HEAD) a := line[beg+2 : middle] b := line[middle+3:] if hasQuote { a = string(git.UnescapeChars([]byte(a[1 : len(a)-1]))) b = string(git.UnescapeChars([]byte(b[1 : len(b)-1]))) } curFile = &DiffFile{ Name: a, Index: len(diff.Files) + 1, Type: DIFF_FILE_CHANGE, Sections: make([]*DiffSection, 0, 10), } diff.Files = append(diff.Files, curFile) if len(diff.Files) >= maxFiles { diff.IsIncomplete = true io.Copy(ioutil.Discard, reader) break } curFileLinesCount = 0 // Check file diff type and is submodule. for { line, err := input.ReadString('\n') if err != nil { if err == io.EOF { isEOF = true } else { return nil, fmt.Errorf("ReadString: %v", err) } } switch { case strings.HasPrefix(line, "new file"): curFile.Type = DIFF_FILE_ADD curFile.IsCreated = true case strings.HasPrefix(line, "deleted"): curFile.Type = DIFF_FILE_DEL curFile.IsDeleted = true case strings.HasPrefix(line, "index"): curFile.Type = DIFF_FILE_CHANGE case strings.HasPrefix(line, "similarity index 100%"): curFile.Type = DIFF_FILE_RENAME curFile.IsRenamed = true curFile.OldName = curFile.Name curFile.Name = b } if curFile.Type > 0 { if strings.HasSuffix(line, " 160000\n") { curFile.IsSubmodule = true } break } } } } // FIXME: detect encoding while parsing. var buf bytes.Buffer for _, f := range diff.Files { buf.Reset() for _, sec := range f.Sections { for _, l := range sec.Lines { buf.WriteString(l.Content) buf.WriteString("\n") } } charsetLabel, err := base.DetectEncoding(buf.Bytes()) if charsetLabel != "UTF-8" && err == nil { encoding, _ := charset.Lookup(charsetLabel) if encoding != nil { d := encoding.NewDecoder() for _, sec := range f.Sections { for _, l := range sec.Lines { if c, _, err := transform.String(d, l.Content); err == nil { l.Content = c } } } } } } return diff, nil }