Commit f660b111 authored by Kevin Lyda's avatar Kevin Lyda
Browse files

Make folder creation configurable

parent 563a1760
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -46,6 +46,13 @@ const (
	FolderPrivate     int64 = 2
)

// Values for CreateFolder setting.
const (
	CreateFolderAdmins int64 = 0
	CreateFolderOwners int64 = 1
	CreateFolderAnyone int64 = 2
)

// CreateFolder creates a new folder.
func CreateFolder(login string, options storage.CreateFolderParams) error {
	if !IsAlphaNum(options.Name) {
@@ -57,9 +64,22 @@ func CreateFolder(login string, options storage.CreateFolderParams) error {
	if err != nil {
		return err
	}

	switch this.System.CreateFolder {
	case CreateFolderAnyone:
		// Anyone can create folders.
	case CreateFolderOwners:
		if admin != 1 {
			owned, err := this.Q.IsAnyFolderOwner(ctx, login)
			if err != nil || owned != 1 {
				return errors.New("only admins or folder owners can create folders")
			}
		}
	default: // CreateFolderAdmins
		if admin != 1 {
			return errors.New("only admins can create folders")
		}
	}

	options.Name = strings.ToUpper(options.Name)

+30 −8
Original line number Diff line number Diff line
@@ -231,7 +231,7 @@ The folder-name is limited to 25 letters and must not include spaces or
characters that are also invalid  in  filenames  (this  is  because  the
folder is stored in a file name created with the folder name).

NOTE:  Creation  of folders is a privileged command.`,
NOTE:  Who can create folders depends on the SET CREATE policy.`,
		Action:  ActionCreate,
		MinArgs: 1,
		MaxArgs: 1,
@@ -1158,14 +1158,29 @@ characteristics of the BULLETIN Utility.

The following options are available:

  ACCESS           ALWAYS           BRIEF            DEFAULT_EXPIRE
  EXPIRE_LIMIT     FOLDER           NOACCESS         NOALWAYS
  NOBRIEF          NOPROMPT_EXPIRE  NOREADNEW        NOSHOWNEW
  NOSYSTEM         PROMPT_EXPIRE    READNEW          REGISTRATION
  SHOWNEW          SHIBBOLETH       SYSTEM
  ACCESS           ALWAYS           BRIEF            CREATE
  DEFAULT_EXPIRE   EXPIRE_LIMIT     FOLDER           NOACCESS
  NOALWAYS         NOBRIEF          NOPROMPT_EXPIRE  NOREADNEW
  NOSHOWNEW        NOSYSTEM         PROMPT_EXPIRE    READNEW
  REGISTRATION     SHOWNEW          SHIBBOLETH       SYSTEM
`,
		Action: ActionSet,
		Commands: dclish.Commands{
			"CREATE": {
				Description: `Controls who is allowed to create new folders.

  Format:
    SET CREATE ANYONE|OWNERS|ADMINS

  ANYONE  - Any user can create a folder.
  OWNERS  - Admins and existing folder owners can create a folder.
  ADMINS  - Only admins can create a folder (default).

This is a privileged command.`,
				MinArgs: 1,
				MaxArgs: 1,
				Action:  ActionSetCreate,
			},
			"REGISTRATION": {
				Description: `Controls  open  registration.  When  open,   unknown  SSH  keys  can
self-onboard via the AuthorizedKeysCommand flow.
@@ -1551,11 +1566,18 @@ that folder cannot be removed.`,

The following options are available:

  FLAGS       FOLDER      NEW         PRIVILEGES  SYSTEM      USER
  VERSION
  CREATE      FLAGS       FOLDER      NEW         PRIVILEGES  SYSTEM
  USER        VERSION
`,
		Action: ActionShow,
		Commands: dclish.Commands{
			"CREATE": {
				Description: `Shows the current folder creation policy.

  Format:
    SHOW CREATE`,
				Action: ActionShowCreate,
			},
			"FLAGS": {
				Description: `Shows whether BRIEF, READNEW, or SHOWNEW has been set for the
currently selected folder.
+35 −0
Original line number Diff line number Diff line
@@ -279,6 +279,41 @@ func ActionSetNosystem(_ *dclish.Command) error {
	return this.Q.UpdateFolderSystem(ctx, 0, this.Folder.Name)
}

// ActionSetCreate handles the `SET CREATE` command.
func ActionSetCreate(cmd *dclish.Command) error {
	if this.User.Admin == 0 {
		return errors.New("privileges needed for changing defaults")
	}
	if len(cmd.Args) != 1 {
		fmt.Println("Usage: SET CREATE ANYONE|OWNERS|ADMINS")
		return nil
	}
	ctx := storage.Context()
	switch strings.ToUpper(cmd.Args[0]) {
	case "ANYONE":
		if err := this.Q.UpdateCreateFolder(ctx, folders.CreateFolderAnyone); err != nil {
			return err
		}
		this.System.CreateFolder = folders.CreateFolderAnyone
		fmt.Println("Folder creation set to: anyone can create folders.")
	case "OWNERS":
		if err := this.Q.UpdateCreateFolder(ctx, folders.CreateFolderOwners); err != nil {
			return err
		}
		this.System.CreateFolder = folders.CreateFolderOwners
		fmt.Println("Folder creation set to: admins and folder owners can create folders.")
	case "ADMINS":
		if err := this.Q.UpdateCreateFolder(ctx, folders.CreateFolderAdmins); err != nil {
			return err
		}
		this.System.CreateFolder = folders.CreateFolderAdmins
		fmt.Println("Folder creation set to: only admins can create folders.")
	default:
		fmt.Println("Usage: SET CREATE ANYONE|OWNERS|ADMINS")
	}
	return nil
}

// ActionSetRegistration handles the `SET REGISTRATION` command.
func ActionSetRegistration(cmd *dclish.Command) error {
	if this.User.Admin == 0 {
+13 −0
Original line number Diff line number Diff line
@@ -43,6 +43,19 @@ func ActionShowFlags(_ *dclish.Command) error {
	return nil
}

// ActionShowCreate handles the `SHOW CREATE` command.
func ActionShowCreate(_ *dclish.Command) error {
	switch this.System.CreateFolder {
	case folders.CreateFolderOwners:
		fmt.Println("Folder creation: admins and folder owners can create folders.")
	case folders.CreateFolderAnyone:
		fmt.Println("Folder creation: anyone can create folders.")
	default:
		fmt.Println("Folder creation: only admins can create folders.")
	}
	return nil
}

// ActionShowFolder handles the `SHOW FOLDER` command.  This is based on
// `SHOW_FOLDER` in bulletin5.for.
func ActionShowFolder(cmd *dclish.Command) error {
+14 −0
Original line number Diff line number Diff line
@@ -116,6 +116,20 @@ func (q *Queries) GetFolderExpire(ctx context.Context, name string) (int64, erro
	return expire, err
}

const isAnyFolderOwner = `-- name: IsAnyFolderOwner :one
SELECT 1 FROM folders WHERE owner = ? LIMIT 1
`

// IsAnyFolderOwner returns true if a user owns at least one folder.
//
//	SELECT 1 FROM folders WHERE owner = ? LIMIT 1
func (q *Queries) IsAnyFolderOwner(ctx context.Context, owner string) (int64, error) {
	row := q.db.QueryRowContext(ctx, isAnyFolderOwner, owner)
	var column_1 int64
	err := row.Scan(&column_1)
	return column_1, err
}

const isFolderOwner = `-- name: IsFolderOwner :one
SELECT 1 FROM folders WHERE name = ? AND owner = ?
`
Loading