// grant/deny user database access parser func (p *Parser) parseUserDatabaseAccessCmd(ctx string) { _token := p.expect(itemString, ctx) _user, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted username in %s", ctx) } _token = p.expect(itemString, ctx) _db, err2 := formatString(_token.val) if err2 != nil { p.errorf("Improperly quoted database in %s", ctx) } _token = p.expect(itemIdentifier, ctx) _grant := false switch _token.val { case "grant": _grant = true case "deny": // do nothing _grant already false break default: p.errorf("Invalid indentifier "+_token.val+" in %s", ctx) } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: true, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Args["username"] = _user cmd.Args["database"] = _db cmd.Args["grant"] = _grant cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// list directory contents parser func (p *Parser) parseListDirectoryCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path // parse arguments ac := newOptList() ac.Add("regex", optString) p.parseOptions(ctx, ac) // get arguments arg := ac.Get("regex") if arg != nil { cmd.Options["regex"] = arg } _filter := p.parseEndofCommand(ctx) cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// initialize bytengine parser func (p *Parser) parseServerInitCmd(ctx string) { _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: true, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// read file JSON content parser func (p *Parser) parseReadFileCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val // check if we have an array of fields to return _list := []string{} if p.peek().typ == itemLeftBracket { // parse array and make sure all elements are strings // absorb left bracket p.next() // check type of next token Loop: for { switch p.peek().typ { case itemString: _next := p.next() _val, err := formatString(_next.val) if err != nil { p.errorf("Improperly quoted string value in %s Array definition.", ctx) } _list = append(_list, _val) continue case itemComma: // absorb comma p.next() if p.peek().typ == itemRightBracket { p.errorf("Trailing comma ',' in %s Array definition.", ctx) } continue case itemRightBracket: // absorb p.next() break Loop default: p.errorf("Invalid value: "+p.peek().val+" in %s Array definition.", ctx) } } } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path cmd.Args["fields"] = _list cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// delete file bytes parser func (p *Parser) parseDeleteAttachmentCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// delete user parser func (p *Parser) parseDropUserCmd(ctx string) { _token := p.expect(itemString, ctx) _user, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted username in %s", ctx) } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: true, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Args["username"] = _user cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// rename file/directory parser func (p *Parser) parseRenameContentCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val _token = p.expect(itemString, ctx) _name, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted new name in %s", ctx) } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path cmd.Args["name"] = _name cmd.Filter = _filter p.commands = append(p.commands, cmd) }
func getUploadTicketHandler(ctx *gin.Context) { var form struct { Token string `form:"token" binding:"required"` Database string `form:"database" binding:"required"` Path string `form:"path" binding:"required"` } ok := ctx.Bind(&form) if ok != nil { data := errorResponse(errors.New("Missing parameters")) ctx.Data(400, "application/json", data) return } cmd := bytengine.Command{ Name: "uploadticket", IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = form.Database cmd.Args["path"] = form.Path duration := Configuration.Timeout.UploadTicket // in minutes cmd.Args["duration"] = duration req := EngineRequest{ Token: form.Token, Command: &cmd, ResponseChan: make(chan EngineResponse), } EngineRequestChan <- &req rep := <-req.ResponseChan if rep.Error != nil { data := errorResponse(rep.Error) ctx.Data(400, "application/json", data) return } ctx.Data(200, "application/json", okResponse(rep.Response)) }
// list users parser func (p *Parser) parseListUsersCmd(ctx string) { cmd := bytengine.Command{ Name: ctx, IsAdmin: true, Args: make(map[string]interface{}), Options: make(map[string]interface{})} // check if regex option has been added // parse arguments ac := newOptList() ac.Add("regex", optString) p.parseOptions(ctx, ac) // get arguments arg := ac.Get("regex") if arg != nil { cmd.Options["regex"] = arg } _filter := p.parseEndofCommand(ctx) cmd.Filter = _filter p.commands = append(p.commands, cmd) }
func downloadFileHandler(ctx *gin.Context) { var form struct { Token string `form:"token" binding:"required"` Database string `form:"database" binding:"required"` Path string `form:"path" binding:"required"` } ok := ctx.Bind(&form) if ok != nil { data := errorResponse(errors.New("Missing parameters")) ctx.Data(400, "application/json", data) return } cmd := bytengine.Command{ Name: "readbytes", IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = form.Database cmd.Args["path"] = form.Path cmd.Args["writer"] = ctx.Writer ctx.Writer.Header().Set("Content-Type", "application/octet-stream") req := EngineRequest{ Token: form.Token, Command: &cmd, ResponseChan: make(chan EngineResponse), } EngineRequestChan <- &req rep := <-req.ResponseChan if rep.Error != nil { data := errorResponse(rep.Error) ctx.String(400, string(data)) return } }
// overwrite file JSON parser func (p *Parser) parseModifyFileCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val // check if next item is a json object var _json interface{} if p.peek().typ == itemLeftBrace { _json = p.parseJSON(ctx) } else { p.errorf("Expecting a JSON object in %s", ctx) } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path cmd.Args["data"] = _json cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// copy file/directory parser func (p *Parser) parseCopyContentCmd(db, ctx string) { _token := p.expect(itemPath, ctx) _path := _token.val _token = p.expect(itemPath, ctx) _path2 := _token.val _rename := "" if p.peek().typ == itemString { _nxt := p.next() _rename = _nxt.val } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["path"] = _path cmd.Args["to"] = _path2 cmd.Args["rename"] = _rename cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// select query statement parser func (p *Parser) parseSelectCmd(db, ctx string) { _fields := []string{} // get fields for p.peek().typ == itemString { _token := p.next() _field, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted field name in %s", ctx) } _fields = append(_fields, FieldPrefix+_field) continue } // get directories _in := p.expect(itemIdentifier, ctx) if strings.ToLower(_in.val) != "in" { p.errorf("Invalid %s, expecting 'In statement'.", ctx) } _paths := []string{} for p.peek().typ == itemPath { _path := p.next().val _paths = append(_paths, _path) continue } cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["fields"] = _fields cmd.Args["dirs"] = _paths var _filter string // get optional identifiers Loop: for { switch _token := p.next(); { case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "where": _where := p.parseWhereCmd() cmd.Args["where"] = _where continue case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "sort": cmd.Args["sort"] = p.parseSortCmd() continue case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "limit": // add to select statement cmd.Args["limit"] = p.parseLimitCmd() continue case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "distinct": // add to select statement cmd.Args["distinct"] = p.parseDistinctCmd() continue case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "count": cmd.Args["count"] = true continue case _token.typ == itemSendTo: p.backup() _filter = p.parseEndofCommand(ctx) break Loop case _token.typ == itemSemiColon: break Loop case _token.typ == itemEOF: p.backup() break Loop default: p.errorf("Invalid identifier "+_token.val+" in %s", ctx) } } // validate select statement _, hascount := cmd.Args["count"] _, haslimit := cmd.Args["limit"] _, hassort := cmd.Args["sort"] _, hasdistinct := cmd.Args["distinct"] if haslimit || hassort { if hascount { p.errorf("'Count' cannot be used with 'Limit' or 'Sort' in %s", ctx) } if hasdistinct { p.errorf("'Distinct' cannot be used with 'Limit' or 'Sort' in %s", ctx) } } else if hasdistinct { if haslimit { p.errorf("'Limit' cannot be used with 'Distinct' in %s", ctx) } if hassort { p.errorf("'Sort' cannot be used with 'Distinct' in %s", ctx) } if hascount { p.errorf("'Count' cannot be used with 'Distinct' in %s", ctx) } } else if hascount { if haslimit { p.errorf("'Limit' cannot be used with 'Count' in %s", ctx) } if hassort { p.errorf("'Sort' cannot be used with 'Count' in %s", ctx) } if hasdistinct { p.errorf("'Distinct' cannot be used with 'Count' in %s", ctx) } } cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// increment/decrement/list counter parser func (p *Parser) parseCounterCmd(db, ctx string) { _token := p.expectOneOf(itemString, itemIdentifier, ctx) if _token.typ == itemIdentifier { if _token.val == "list" { cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["action"] = "list" // parse arguments ac := newOptList() ac.Add("regex", optString) p.parseOptions(ctx, ac) // get arguments arg := ac.Get("regex") if arg != nil { cmd.Options["regex"] = arg } _filter := p.parseEndofCommand(ctx) cmd.Filter = _filter p.commands = append(p.commands, cmd) return } else { p.errorf("Invalid identifier %s in %s", _token.val, ctx) } } _counter, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted counter name in %s", ctx) } _token = p.expect(itemIdentifier, ctx) _action := "" switch _token.val { case "incr": fallthrough case "decr": fallthrough case "reset": _action = _token.val default: p.errorf("Invalid indentifier "+_token.val+" in %s", ctx) } _token = p.expect(itemNumber, ctx) _val, err := strconv.ParseInt(_token.val, 10, 64) // base 10 64bit integer if err != nil { p.errorf("Invalid numerical value in %s", ctx) } _filter := p.parseEndofCommand(ctx) cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["name"] = _counter cmd.Args["action"] = _action cmd.Args["value"] = _val cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// unset query statement parser func (p *Parser) parseUnsetCmd(db, ctx string) { _fields := map[string]interface{}{} // get fields for p.peek().typ == itemString { _token := p.next() _field, err := formatString(_token.val) if err != nil { p.errorf("Improperly quoted field name in %s", ctx) } _field = FieldPrefix + _field _fields[_field] = 1 continue } if len(_fields) < 1 { p.errorf("Invalid %s: no fields found", ctx) } // get directories _in := p.expect(itemIdentifier, ctx) if strings.ToLower(_in.val) != "in" { p.errorf("Invalid %s, expecting 'In statement'.", ctx) } _paths := []string{} for p.peek().typ == itemPath { _path := p.next().val _paths = append(_paths, _path) continue } cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["fields"] = _fields cmd.Args["dirs"] = _paths var _filter string // get optional identifiers Loop2: for { switch _token := p.next(); { case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "where": _where := p.parseWhereCmd() cmd.Args["where"] = _where continue case _token.typ == itemSendTo: p.backup() _filter = p.parseEndofCommand(ctx) break Loop2 case _token.typ == itemSemiColon: break Loop2 case _token.typ == itemEOF: // do not consume eof p.backup() break Loop2 default: p.errorf("Invalid identifier "+_token.val+" in %s", ctx) } } cmd.Filter = _filter p.commands = append(p.commands, cmd) }
// set query statement parser func (p *Parser) parseSetCmd(db, ctx string) { _fields := map[string]interface{}{} _incr := map[string]interface{}{} // get field assignment list Loop: for { switch i := p.next(); i.typ { case itemString: switch p.peek().typ { case itemEqual: p.backup2(i) f, v := p.parseValueAssignment() _fields[f] = v continue case itemPlusEqual: fallthrough case itemMinusEqual: p.backup2(i) f, v := p.parseIncrDecrValue() _incr[f] = v continue default: p.errorf("Invalid assingment operator in %s", ctx) } default: p.backup() break Loop } } if len(_fields) < 1 && len(_incr) < 1 { p.errorf("Invalid %s: no field assignments found", ctx) } // get directories _in := p.expect(itemIdentifier, ctx) if strings.ToLower(_in.val) != "in" { p.errorf("Invalid %s, expecting 'In statement'.", ctx) } _paths := []string{} for p.peek().typ == itemPath { _path := p.next().val _paths = append(_paths, _path) continue } cmd := bytengine.Command{ Name: ctx, IsAdmin: false, Args: make(map[string]interface{}), Options: make(map[string]interface{}), } cmd.Database = db cmd.Args["fields"] = _fields if len(_incr) > 0 { cmd.Args["incr"] = _incr } cmd.Args["dirs"] = _paths var _filter string // get optional identifiers Loop2: for { switch _token := p.next(); { case _token.typ == itemIdentifier && strings.ToLower(_token.val) == "where": _where := p.parseWhereCmd() cmd.Args["where"] = _where continue case _token.typ == itemSendTo: p.backup() _filter = p.parseEndofCommand(ctx) break Loop2 case _token.typ == itemSemiColon: break Loop2 case _token.typ == itemEOF: // do not consume eof p.backup() break Loop2 default: p.errorf("Invalid identifier "+_token.val+" in %s", ctx) } } cmd.Filter = _filter p.commands = append(p.commands, cmd) }