turbo-src / chrome-extension

MIT License
2 stars 4 forks source link

Don't have proper scope for authenticating tokenizers. #39

Closed 7db9a closed 2 years ago

7db9a commented 2 years ago

As part of the tokenization process, tokenizers must re-authenticate with requested scope. Should automatically request public_repo scope when they click "tokenize". If possible, set it so it doesn't default to expire. Believe you can set it so it doesn't. We're not interested in repo, which includes private repo access.

UPDATE: think we'll have to deal with expiring tokens. They expire every 8 hours. To my understanding, you make a request with the old token and you get a new one. This can be done server-side so the Turbosrc services can take care of this.

https://docs.github.com/en/developers/apps/building-github-apps/refreshing-user-to-server-access-tokens

jex441 commented 2 years ago

On the branch called scope there is functionality to check the scopes of a user before they tokenize. If their scopes are only user:email, a message is rendered asking them to update their scopes. Clicking the button authenticates them through Github with the public_repo scope in addition to user:email.

When the user visits the tokenize page again, the warning message is not rendered and they can click the button to tokenize the current repository.

An additional NPM package was used to achieve this: Octokit. The core functionality is in Onboard2.js and is copied here:

useEffect(()=>{

// Function declared:
const checkScope = async() => {
if(!repo || !owner){
return
}

const octokit = new Octokit({ auth: user.token });
const res = await octokit.request(`GET /repos/${owner}/${repo}`)

Promise.resolve(res).then((object) => {
if(object.headers['x-oauth-scopes'].split(',').includes('public_repo')) {
setVerified(true)
} else {
setVerified(false)
}})}

// Function called:
checkScope()

}, [owner,repo])

Setting verified to true will cause the warning message not to render and enable the tokenize button to createRepo.

There is likely room for optimization here. For example, perhaps we can check the scopes of a user's tokens without Octokit. However, in the likely scenario we not only want to verify whether or not a user's token has the public_repo scope but whether or not they actually have read/write access to the repository they want to tokenize, I believe we could achieve that too here.

Also, we may decide to move this logic to a turbosrc-service API call and handle the Octokit functionality there. We could remove the logic above and add an API call called checkScopes which queries GithubUtils in turbosrc-service via the GraphQL server.

jex441 commented 2 years ago

To ensure a user has admin/maintainer/push permissions to the current repo in addition to having the public_repo scope enabled we can see the permissions value in the response from Github which is console logged on the left:

One of my repos which I have permissions for based on my token:

Screen Shot 2022-09-19 at 10 42 08 AM

Not a repo I have permissions for based on my token:

Screen Shot 2022-09-19 at 10 41 07 AM

So the second screenshot should not render the Submit button, but rather a second warning saying something to the effect of "You do not have permissions to this repository". And possibly suggesting that they fork the repository instead or a field where they can enter a valid API key for that repository.

Would be interested to hear what you think.

jex441 commented 2 years ago

The most recent push to the branch scope has the following functionality:

A user tries to tokenize a repo for the first time

They are given a warning to update their permissions, which takes them through Github authentication with the proper scope added: public_repo. They can then tokenize one of their repositories:

Screen Shot 2022-09-20 at 10 51 48 AM

A user completes the above step and is trying to tokenize a repo they do not have access to

They are prompted to enter a valid access token for the requested repository:

Screen Shot 2022-09-20 at 10 52 07 AM

They copy and paste an access token which is valid for that repository

They can then tokenize the repo:

Screen Shot 2022-09-20 at 10 52 15 AM

Their access token is not valid

They can not proceed until they have a valid access token:

Screen Shot 2022-09-20 at 10 53 00 AM

This was achieved by having two functions which check both the scopes a user has for their token and the permissions the user has for a given repo. Checkscope has changed to only check a tokens scopes for a user:

  const checkScope = async(token) => {
    if(!repo || !owner){
      return
    }
  const octokit = new Octokit({ auth: token });
  const res = await octokit.request(`GET /users/${user.login}`)

  Promise.resolve(res).then((object) => {
    if(object.headers['x-oauth-scopes'].split(',').includes('public_repo')) {
      setScope(true)
    } else {
      setScope(false)
    }
  })
}

And checkPermissions functions in a similar fashion checking the tokens permissions for a certain repo:

const checkPermissions = async(token) => {
  if(!repo || !owner){
    return
  }
const octokit = new Octokit({ auth: token });
const res = await octokit.request(`GET /repos/${owner}/${repo}`)

Promise.resolve(res).then((object) => {
  if(object.data.permissions.push) {
    setPermissions(true)
  } else {
    setPermissions(false)
  }
})
}

There could be a scenario where a user does not want to grant public_repo permissions to Turbosrc for their repos but does want to tokenize a repo, say belonging to a colleague, for which they have a working access_token. We do not have functionality for this but it would not be hard to implement. We have everything we need.