Пример #1
0
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)
	}
}
Пример #2
0
// GitFsck calls 'git fsck' to check repository health.
func GitFsck() {
	if isGitFscking {
		return
	}
	isGitFscking = true
	defer func() { isGitFscking = false }()

	log.Trace("Doing: GitFsck")

	args := append([]string{"fsck"}, setting.Cron.RepoHealthCheck.Args...)
	if err := x.Where("id>0").Iterate(new(Repository),
		func(idx int, bean interface{}) error {
			repo := bean.(*Repository)
			repoPath, err := repo.RepoPath()
			if err != nil {
				return fmt.Errorf("RepoPath: %v", err)
			}

			_, _, 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, "CreateRepositoryNotice: %v", err)
				}
			}
			return nil
		}); err != nil {
		log.Error(4, "GitFsck: %v", err)
	}
}
Пример #3
0
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")
}
Пример #4
0
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")
}
Пример #5
0
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: 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

		// Diff data too large, we only show the first about maxlines lines
		if i == maxlines {
			isTooLong = true
			log.Warn("Diff data too large")
		}

		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 {
				break
			}

			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) {
			if isTooLong {
				break
			}

			beg := len(DIFF_HEAD)
			a := line[beg : (len(line)-beg)/2+beg]

			// In case file name is surrounded by double quotes(it happens only in git-shell).
			if a[0] == '"' {
				a = a[1 : len(a)-1]
				a = strings.Replace(a, `\"`, `"`, -1)
			}

			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
				}
			}
		}
	}

	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
}
Пример #6
0
// DeleteRepository deletes a repository for a user or organization.
func DeleteRepository(uid, repoID int64) 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 and attachments.
	issues := make([]*Issue, 0, 25)
	attachmentPaths := make([]string, 0, len(issues))
	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
		}

		attachments := make([]*Attachment, 0, 5)
		if err = sess.Where("issue_id=?", issues[i].ID).Find(&attachments); err != nil {
			return err
		}
		for j := range attachments {
			attachmentPaths = append(attachmentPaths, attachments[j].LocalPath())
		}

		if _, err = sess.Delete(&Attachment{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 fmt.Errorf("decrease fork count: %v", err)
		} else if _, err = sess.Delete(&ForkInfo{RepoID: repo.ID}); err != nil {
			return fmt.Errorf("delete fork info: %v", err)
		}
	}

	if _, err = sess.Exec("UPDATE `user` SET num_repos=num_repos-1 WHERE id=?", uid); err != nil {
		return err
	}

	// Remove repository files.
	repoPath, err := repo.RepoPath()
	if err != nil {
		return fmt.Errorf("RepoPath: %v", err)
	}
	if err = os.RemoveAll(repoPath); err != nil {
		desc := fmt.Sprintf("delete repository files[%s]: %v", repoPath, err)
		log.Warn(desc)
		if err = CreateRepositoryNotice(desc); err != nil {
			log.Error(4, "add notice: %v", err)
		}
	}

	// Remove attachment files.
	for i := range attachmentPaths {
		if err = os.Remove(attachmentPaths[i]); err != nil {
			log.Warn("delete attachment: %v", err)
		}
	}

	if err = sess.Commit(); err != nil {
		return fmt.Errorf("Commit: %v", err)
	}

	if repo.NumForks > 0 {
		if repo.IsPrivate {
			forkRepos, err := GetRepositoriesByForkID(repo.ID)
			if err != nil {
				return fmt.Errorf("getRepositoriesByForkID: %v", err)
			}
			for i := range forkRepos {
				if err = DeleteRepository(forkRepos[i].OwnerID, forkRepos[i].ID); err != nil {
					log.Error(4, "updateRepository[%d]: %v", forkRepos[i].ID, err)
				}
			}
		} else {
			if _, err = x.Exec("UPDATE `repository` SET fork_id=0,is_fork=? WHERE fork_id=?", false, repo.ID); err != nil {
				log.Error(4, "reset 'fork_id' and 'is_fork': %v", err)
			}
			if _, err = x.Delete(&ForkInfo{ForkID: repo.ID}); err != nil {
				log.Error(4, "clear fork infos: %v", err)
			}
		}
	}

	return nil
}
Пример #7
0
// 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 = 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

	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()
	SSHDomain = sec.Key("SSH_DOMAIN").MustString(Domain)
	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 = strings.Replace(sec.Key("ALLOWED_TYPES").MustString("image/jpeg,image/png"), "|", ",", -1)
	AttachmentMaxSize = sec.Key("MAX_SIZE").MustInt64(32)
	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()
	curUser := user.CurrentUsername()
	// 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")
	AnsiCharset = sec.Key("ANSI_CHARSET").MustString("")

	// UI settings.
	sec = Cfg.Section("ui")
	ExplorePagingNum = sec.Key("EXPLORE_PAGING_NUM").MustInt(20)
	IssuePagingNum = sec.Key("ISSUE_PAGING_NUM").MustInt(10)

	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 source := sec.Key("GRAVATAR_SOURCE").MustString("gravatar"); source {
	case "duoshuo":
		GravatarSource = "http://gravatar.duoshuo.com/avatar/"
	case "gravatar":
		GravatarSource = "//1.gravatar.com/avatar/"
	default:
		GravatarSource = source
	}
	DisableGravatar = sec.Key("DISABLE_GRAVATAR").MustBool()
	if OfflineMode {
		DisableGravatar = true
	}

	if err = Cfg.Section("markdown").MapTo(&Markdown); err != nil {
		log.Fatal(4, "Fail to map Markdown 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 Cfg.Section("cron").MapTo(&Cron); err != nil {
		log.Fatal(4, "Fail to map Cron settings: %v", err)
	}

	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()

	HasRobotsTxt = com.IsFile(path.Join(CustomPath, "robots.txt"))
}
Пример #8
0
// 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.ValidatePassword(passwd) {
			return nil, ErrUserNotExist{u.Id, u.Name}
		}
		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)
			} else if source.Type == PAM {
				u, err := LoginUserPAMSource(nil, uname, passwd,
					source.ID, source.Cfg.(*PAMConfig), true)
				if err == nil {
					return u, nil
				}
				log.Warn("Fail to login(%s) by PAM(%s): %v", uname, source.Name, err)
			}
		}

		return nil, ErrUserNotExist{u.Id, u.Name}
	}

	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)
	case PAM:
		return LoginUserPAMSource(u, u.LoginName, passwd, source.ID, source.Cfg.(*PAMConfig), false)
	}
	return nil, ErrUnsupportedLoginType
}