_require: 
    crypto: crypto
    fs: fs
authenticate:
    type: Goal
    build:
        __goal__: 
            type: FlowAll
            name: choose_method
        choose_method:
            options:
                none_reason: 
                    code: 404
                    message: 'No valid authentication method provided'
            type: FlowAll
            when:
            -   cond: |
                    const req = payload.data
                    return req.headers && req.headers.authorization && /^Basic /.test(req.headers.authorization)
                dst:
                    type: Transform
                    name: parse_basic
            -   cond: |
                    const req = payload.data
                    if(!(req.query && req.query.user && req.query.pass) && !(req.body && req.body.user && req.body.pass)) return false
                    req.auth = {user: req.query.user||req.body.user, pass: req.query.pass||req.body.pass}
                    return true
                dst:
                    type: FlowFirst
                    name: first_auth
            -   cond: |
                    const req = payload.data
                    return (req.query && req.query.token) || (req.headers && req.headers.authorization && /^Bearer /.test(req.headers.authorization))
                dst:
                    type: Transform
                    name: parse_token
            none: __reject__
            once:
                prefinish:
                    code: |
                        const payload = new DataWrapper(this.goal._src, this);
                        this._write(payload, null, ()=>{});
        parse_basic:
            type: Transform
            methods:
                transform:
                    code: |
                        let basic = payload.data.headers.authorization.replace(/^Basic (.*)$/, (str, match)=>match);
                        let auth_array = Buffer.from(basic, 'base64').toString('utf8').split(':');
                        payload.data.auth = {user: auth_array[0], pass: auth_array[1]};
                        this.push(payload);
                        cb()
                    params:
                        - payload
                        - encoding
                        - cb
            pipe:
                type: FlowFirst
                name: first_auth
        first_auth:
            type: FlowFirst
            methods:
                identify:
                    code: |
                        return payload.map.FlowAll.choose_method
                    params:
                        - payload
            pipe:
                type: Transform
                name: validate_user
        parse_token:
            type: Transform
            methods:
                transform:
                    code: |
                        try {
                          const tokens = JSON.parse(fs.readFileSync('./tokens.json')).tokens
                          const token = (payload.data.query && payload.data.query.token) || payload.data.headers.authorization.replace(/^Bearer (.*)$/, (str, match)=>match)
                          if(!tokens.hasOwnProperty(token)) return callback(payload.getChild(this).setData({code: 401, message: 'Invalid token'}))
                          payload.data.userid = tokens[token]
                          this.push(payload)
                          callback()
                        } catch(e) {
                          callback(payload.getChild(this).setData({code: 500, message: e.message}))
                        }
                    params:
                        - payload
                        - encoding
                        - callback
            pipe: __resolve__
        validate_user:
            type: Transform
            methods:
                transform:
                    code: |
                        try {
                          const users = JSON.parse(fs.readFileSync('./users.json')).users
                          const user = users.filter(u => u.user == payload.data.auth.user)
                          if(!user.length) return callback(payload.getChild(this).setData({code: 401, message: 'Incorrect user or password'}))
                          const hash = crypto.createHash(user[0].method)
                          hash.update(payload.data.auth.pass)
                          if(user[0].password != hash.digest('hex')) return callback(payload.getChild(this).setData({code: 401, message: 'Incorrect user or password'}))
                          payload.data.userid = user[0].id
                          delete payload.data.auth
                          this.push(payload)
                          callback()
                        } catch(e) {
                          callback(payload.getChild(this).setData({code: 500, message: e.message}))
                        }
                    params:
                        - payload
                        - encoding
                        - callback
            pipe: __resolve__
authorise:
    type: Goal
    build:
        __goal__: 
            type: Transform
            name: get_user_data
        get_user_data:
            type: Transform
            methods:
                transform:
                    code: |
                        try {
                          const users = JSON.parse(fs.readFileSync('./users.json')).users
                          const user = users.filter(u => u.id == payload.data.userid)
                          if(!user.length) return callback(payload.getChild(this).setData({code: 401, message: 'Incorrect user or password'}))
                          payload.data.user = user[0]
                          this.push(payload)
                          callback()
                        } catch(e) {
                          callback(payload.getChild(this).setData({code: 500, message: e.message}))
                        }
                    params:
                        - payload
                        - encoding
                        - callback
            ponce:
                prefinish:
                    code: |
                        const payload = new DataWrapper(this.goal._src, this);
                        this._write(payload, null, (err)=>{ if(err) this.emit('error', err)});
            pipe:
                type: FlowOne
                name: auth_methods
        auth_methods:
            type: FlowOne
            options:
                none_reason:
                    code: 401
                    message: Unauthorised access
            when:
                cond: |
                    return payload.data.userid == payload.data.params.id || payload.data.user.is_admin
                dst: __resolve__
            none: __reject__
get_user:
    type: Transform
    methods:
        transform:
            code: |
                try {
                  const users = JSON.parse(fs.readFileSync('./users.json')).users
                  const user = users.filter(u => u.id == payload.params.id)
                  if(!user.length) return callback({code: 404, message: 'User not found'})
                  this.push(JSON.stringify(user[0]))
                  callback()
                } catch(e) {
                  callback({code: 500, message: e.message})
                }
            params:
                - payload
                - encoding
                - callback
    on:
        pipe:
            code:
                - this._src = src
            params:
                - src
    ponce:
        prefinish:
            code:
                - this._write(this._src, null, (err)=>{ if(err) this.emit('error', err)});



