Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add token validation and set token in graphql clients #45

Merged
merged 6 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- Add token validation in graphql operations and token to call storefront-permission and b2b-organization

## [2.4.1] - 2023-11-09

### Fixed
Expand Down
1 change: 1 addition & 0 deletions graphql/directives.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ directive @withPermissions on FIELD | FIELD_DEFINITION
directive @withSegment on FIELD | FIELD_DEFINITION
directive @checkAdminAccess on FIELD | FIELD_DEFINITION
directive @auditAccess on FIELD | FIELD_DEFINITION
directive @checkUserAccess on FIELD | FIELD_DEFINITION
2 changes: 1 addition & 1 deletion graphql/schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ type Mutation {
useQuote(id: String, orderFormId: String): String
@withPermissions
@withSession
clearCart(orderFormId: String): String @auditAccess
clearCart(orderFormId: String): String @checkUserAccess
saveAppSettings(input: AppSettingsInput!): AppSettings
@cacheControl(scope: PRIVATE)
@checkAdminAccess
Expand Down
7 changes: 3 additions & 4 deletions manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@
},
"dependencies": {
"vtex.storefront-permissions": "1.x",
"vtex.b2b-organizations-graphql": "0.x",
"vtex.orders-broadcast": "0.x"
},
"registries": [
"smartcheckout"
],
"registries": ["smartcheckout"],
"policies": [
{
"name": "vbase-read-write"
Expand Down Expand Up @@ -48,7 +47,7 @@
"name": "vtex.storefront-permissions:resolve-graphql"
},
{
"name": "vtex.graphql-server:resolve-graphql"
"name": "vtex.b2b-organizations-graphql:resolve-graphql"
},
{
"name": "Get_User_By_Identifier"
Expand Down
17 changes: 16 additions & 1 deletion node/clients/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { IOContext } from '@vtex/api'
import { IOClients } from '@vtex/api'

import RequestHub from '../utils/Hub'
import Identity from '../utils/Identity'
import { Scheduler } from '../utils/Scheduler'
import Checkout from './checkout'
import MailClient from './email'
Expand All @@ -9,7 +11,20 @@ import OrdersClient from './OrdersClient'
import Organizations from './organizations'
import StorefrontPermissions from './storefrontPermissions'
import VtexId from './vtexId'
import Identity from '../utils/Identity'

export const getTokenToHeader = (ctx: IOContext) => {
const token =
ctx.storeUserAuthToken ?? ctx.adminUserAuthToken ?? ctx.authToken

const { sessionToken } = ctx

return {
'x-vtex-credential': ctx.authToken,
VtexIdclientAutCookie: token,
cookie: `VtexIdclientAutCookie=${token}`,
'x-vtex-session': sessionToken,
}
}

// Extend the default IOClients implementation with our own custom clients.
export class Clients extends IOClients {
Expand Down
126 changes: 44 additions & 82 deletions node/clients/organizations.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,14 @@
import type { InstanceOptions, IOContext } from '@vtex/api'
import { AppClient, GraphQLClient } from '@vtex/api'
import { AppGraphQLClient } from '@vtex/api'

export default class Organizations extends AppClient {
protected graphql: GraphQLClient
import { getTokenToHeader } from './index'

export default class Organizations extends AppGraphQLClient {
constructor(ctx: IOContext, options?: InstanceOptions) {
super('[email protected]', ctx, options)
this.graphql = new GraphQLClient(this.http)
}

public getOrganizationIDs = async (search: string): Promise<any> => {
const graphQLQuery = `query GetOrganizations($search: String!) {
getOrganizations(search: $search) {
data {
id
}
}
}`

return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: graphQLQuery,
variables: {
search,
},
},
{ url: '/graphql' }
)
super('[email protected]', ctx, options)
}

public getOrganizationById = async (id: string): Promise<any> => {

Check warning on line 11 in node/clients/organizations.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
const graphQLQuery = `query GetOrganizationById($id: ID!) {
getOrganizationById(id: $id) {
name
Expand All @@ -43,50 +16,16 @@
}
`

return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: graphQLQuery,
variables: {
id,
},
return this.query({
extensions: this.getPersistedQuery(),
query: graphQLQuery,
variables: {
id,
},
{ url: '/graphql' }
)
}

public getCostCenterIDs = async (search: string): Promise<any> => {
const graphQLQuery = `query GetCostCenters($search: String!) {
getCostCenters(search: $search) {
data {
id
}
}
}`

return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: graphQLQuery,
variables: {
search,
},
},
{ url: '/graphql' }
)
})
}

public getCostCenterById = async (id: string): Promise<any> => {

Check warning on line 28 in node/clients/organizations.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
const graphQLQuery = `query GetCostCenterById($id: ID!) {
getCostCenterById(id: $id) {
name
Expand All @@ -94,20 +33,43 @@
}
`

return this.query({
extensions: this.getPersistedQuery(),
query: graphQLQuery,
variables: {
id,
},
})
}

private getPersistedQuery = () => {
return {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
}
}

private query = async (param: {
query: string
variables: any

Check warning on line 56 in node/clients/organizations.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
extensions: any

Check warning on line 57 in node/clients/organizations.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
}): Promise<any> => {

Check warning on line 58 in node/clients/organizations.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
const { query, variables, extensions } = param

return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: graphQLQuery,
variables: {
id,
},
extensions,
query,
variables,
},
{ url: '/graphql' }
{
headers: getTokenToHeader(this.context),
params: {
locale: this.context.locale,
},
}
)
}
}
85 changes: 47 additions & 38 deletions node/clients/storefrontPermissions.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import type { InstanceOptions, IOContext } from '@vtex/api'
import { AppGraphQLClient } from '@vtex/api'

import { getTokenToHeader } from './index'

export const QUERIES = {
getPermission: `query permissions {
checkUserPermission {
Expand Down Expand Up @@ -59,36 +61,20 @@
super('[email protected]', ctx, options)
}

public checkUserPermission = async (): Promise<any> => {

Check warning on line 64 in node/clients/storefrontPermissions.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: QUERIES.getPermission,
variables: {},
},
{}
)
return this.query({
extensions: this.getPersistedQuery(),
query: QUERIES.getPermission,
variables: {},
})
}

public listRoles = async (): Promise<any> => {

Check warning on line 72 in node/clients/storefrontPermissions.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: QUERIES.listRoles,
variables: {},
},
{}
)
return this.query({
extensions: this.getPersistedQuery(),
query: QUERIES.listRoles,
variables: {},
})
}

public listUsers = async ({
Expand All @@ -97,22 +83,45 @@
}: {
roleId: string
organizationId?: string
}): Promise<any> => {

Check warning on line 86 in node/clients/storefrontPermissions.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
return this.query({
extensions: this.getPersistedQuery(),
query: QUERIES.listUsers,
variables: {
roleId,
...(organizationId && { organizationId }),
},
})
}

private getPersistedQuery = () => {
return {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
}
}

private query = async (param: {
query: string
variables: any

Check warning on line 108 in node/clients/storefrontPermissions.ts

View workflow job for this annotation

GitHub Actions / QE / Lint Node.js

Unexpected any. Specify a different type
extensions: any
}): Promise<any> => {
const { query, variables, extensions } = param

return this.graphql.query(
{
extensions: {
persistedQuery: {
provider: '[email protected]',
sender: '[email protected]',
},
},
query: QUERIES.listUsers,
variables: {
roleId,
...(organizationId && { organizationId }),
},
extensions,
query,
variables,
},
{}
{
headers: getTokenToHeader(this.context),
params: {
locale: this.context.locale,
},
}
)
}
}
4 changes: 2 additions & 2 deletions node/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"jsonwebtoken": "^8.5.0",
"ramda": "^0.25.0",
"atob": "^2.1.2",
"axios": "0.27.2"
"axios": "0.27.2",
"@vtex/api": "6.46.0"
},
"devDependencies": {
"@types/atob": "^2.1.2",
Expand All @@ -17,7 +18,6 @@
"@types/jsonwebtoken": "^8.5.0",
"@types/node": "^12.0.0",
"@types/ramda": "types/npm-ramda#dist",
"@vtex/api": "6.45.20",
"@vtex/prettier-config": "^0.3.1",
"tslint": "^5.12.0",
"tslint-config-prettier": "^1.18.0",
Expand Down
8 changes: 5 additions & 3 deletions node/resolvers/directives.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { AuditAccess } from './directives/auditAccess'
import { CheckAdminAccess } from './directives/checkAdminAccess'
import { CheckUserAccess } from './directives/checkUserAccess'
import { WithPermissions } from './directives/withPermissions'
import { WithSession } from './directives/withSession'
import { WithSegment } from './directives/withSegment'
import { CheckAdminAccess } from './directives/checkAdminAccess'
import { AuditAccess } from './directives/auditAccess'
import { WithSession } from './directives/withSession'

export const schemaDirectives = {
withPermissions: WithPermissions as any,
withSession: WithSession as any,
withSegment: WithSegment as any,
checkAdminAccess: CheckAdminAccess as any,
auditAccess: AuditAccess as any,
checkUserAccess: CheckUserAccess as any,
}
Loading
Loading