question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Permissions on Input Types

See original GitHub issue

A use case I’m interested in is putting permissions on input types and individual fields of input types. This would simplify mutation permissions because you could use a generic mutation like updateUser but limit access to modifying certain fields of User.

Is this supported or possible to add? I’d be happy to contribute if interested.

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:5
  • Comments:15

github_iconTop GitHub Comments

7reactions
frankdugan3commented, Aug 5, 2018

I’ll do some digging this week.

2reactions
vadisticcommented, Sep 7, 2018

Hello, I’m just tackling this issue in my project and I thought I will present my progress for inspiration.

I would be glad for any pointers how to improve it. Also - I have literally no idea how this construct affect performance and caching…

So my idea is to treat each input field permissions as separate rule and join them with and(). Here’s example (using ramda a bit, hope it’s still readable)

// Let's prep some syntax sugar

interface FieldRuleMap {
  [key: string]: (field: string) => IRule
}

const fieldRules = (fieldRuleMap: FieldRuleMap) => {
  const rulesArr = Object.entries(fieldRuleMap).map(([key, fn]) => fn(key))
  return and(...rulesArr)
}
// Then define my input field rule

const hasPermission = (fieldName: string) =>
        rule()(async (parent, args, ctx: Context) => {
          // shortcircuit for performance if args has none of this prop
          if (!R.has(fieldName, args)) {
            return true
          }

          // check your privileges
          const res = complicatedCalculations()

          return res
        })
// And voila!

const rulesWithFields: IRules = {
  Mutation: {
    createUser: and(isAuthorized, fieldRules({
      name: hasPermission
    })),
  },
}

const permissions = shield(rulesWithFields)

If you don’t mind wall of code - here’s some real example - I’m forwarding a lot’s of resolvers to Prisma, but I need to check input arguments for connections validity. Here I validate if some target user is a member of the same 'workspace` as user. It’s one-to-many case, for one-to-one I will need to use slightly modified rule.


const verifyConnection = (target: string) => (field: string) =>
  rule()(async (parent, args, ctx: Context) => {
    // shortcircuit
    if (!R.has(field, args.data)) {
      return true
    }

  // I do a lot of this checks so I keep workspaceId in JWT
    const workspaceId = getId(ctx).workspaceId
  // Get id[] from args
    const targetConnect = args.data[field].connect

  // Now I mapping ids to array of promises checking each provided target id
    const validationP = targetConnect.map(connect => {
      return ctx.db.exists[target]({
        AND: {
          id: connect.id,
          workspace: { id: workspaceId },
        },
     // Later I'm using Promise.all() and I want it to stop executing on first `false` so I'm adding reject
      }).then(res => (res === true ? Promise.resolve(true) : Promise.reject('Not Authorized')))
    })
    
   // Await for all promises and test if all elements yield true 
   // (bit unnecessary since I'm rejecting those promises in case of false, but nvm)
    const result = R.all(R.equals(true), await Promise.all(validationP).catch(rej => [false]))

    return result
  })

// same syntetic sugar as previous example
interface ConnectionRuleMap {
  [key: string]: (field: string) => IRule
}

const verifyConnections = (connectionRuleMap: ConnectionRuleMap) => {
  const rulesArr = Object.entries(connectionRuleMap).map(([key, fn]) => fn(key))
  return and(...rulesArr)
}

// rules
export const rules: IRules = {
Mutation: {
    createTask: verifyConnections({
      owners: verifyConnection('User'),
      subscribers: verifyConnection('User'),
    })
  }
}

const permissions = shield(rules)

export default permissions

What y’all think? 😃

// EDIT Btw. I did not tackle how to nicely use logic rules on fields yet without rewiring them

// this will fullfil my needs, but there should be a better way
const fieldAnd = (fieldName: string) => (...args: FieldRule[]) =>
  and(...args.map(arg => arg(fieldName)))
Read more comments on GitHub >

github_iconTop Results From Across the Web

Permissions on Input Types · Issue #113 · dimatill/graphql-shield
A use case I'm interested in is putting permissions on input types and individual fields of input types. This would simplify mutation ...
Read more >
The HTML5 input types - Learn web development | MDN
Objective: To understand the newer input type values available to create native form controls, and how to implement them using HTML. Note: Most ......
Read more >
Permissions on Android - Android Developers
Overview · Standalone apps · Authentication · Request permissions · Detect location ... Kernel invocation functions and types · Input/output functions ...
Read more >
Mobile browser 'Files and media' permission status
I have a simple input for files (especially images) in a page. <input type='file' accept='image/*'/>.
Read more >
Permission to edit a particular text field by a specific user
I have a form in MS Access where two text fields are linked to a table. I want User1 to allow to input/edit...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found