@boxyhq/saml-jackson 0.2.3-beta.228 → 0.2.3-beta.233

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/package.json +8 -2
  2. package/ nodemon.json +0 -12
  3. package/.dockerignore +0 -2
  4. package/.eslintrc.js +0 -18
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -27
  6. package/.github/ISSUE_TEMPLATE/config.yml +0 -5
  7. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -43
  8. package/.github/pull_request_template.md +0 -31
  9. package/.github/workflows/codesee-arch-diagram.yml +0 -81
  10. package/.github/workflows/main.yml +0 -123
  11. package/_dev/docker-compose.yml +0 -37
  12. package/map.js +0 -1
  13. package/prettier.config.js +0 -4
  14. package/src/controller/api.ts +0 -225
  15. package/src/controller/error.ts +0 -13
  16. package/src/controller/oauth/allowed.ts +0 -22
  17. package/src/controller/oauth/code-verifier.ts +0 -11
  18. package/src/controller/oauth/redirect.ts +0 -12
  19. package/src/controller/oauth.ts +0 -337
  20. package/src/controller/utils.ts +0 -17
  21. package/src/db/db.ts +0 -100
  22. package/src/db/encrypter.ts +0 -38
  23. package/src/db/mem.ts +0 -128
  24. package/src/db/mongo.ts +0 -110
  25. package/src/db/redis.ts +0 -103
  26. package/src/db/sql/entity/JacksonIndex.ts +0 -44
  27. package/src/db/sql/entity/JacksonStore.ts +0 -43
  28. package/src/db/sql/entity/JacksonTTL.ts +0 -17
  29. package/src/db/sql/model/JacksonIndex.ts +0 -3
  30. package/src/db/sql/model/JacksonStore.ts +0 -8
  31. package/src/db/sql/sql.ts +0 -181
  32. package/src/db/store.ts +0 -49
  33. package/src/db/utils.ts +0 -26
  34. package/src/env.ts +0 -42
  35. package/src/index.ts +0 -79
  36. package/src/jackson.ts +0 -171
  37. package/src/read-config.ts +0 -29
  38. package/src/saml/claims.ts +0 -41
  39. package/src/saml/saml.ts +0 -234
  40. package/src/saml/x509.ts +0 -51
  41. package/src/test/api.test.ts +0 -270
  42. package/src/test/data/metadata/boxyhq.js +0 -6
  43. package/src/test/data/metadata/boxyhq.xml +0 -30
  44. package/src/test/data/saml_response +0 -1
  45. package/src/test/db.test.ts +0 -313
  46. package/src/test/oauth.test.ts +0 -362
  47. package/src/typings.ts +0 -167
  48. package/tsconfig.build.json +0 -6
  49. package/tsconfig.json +0 -26
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@boxyhq/saml-jackson",
3
- "version": "0.2.3-beta.228",
3
+ "version": "0.2.3-beta.233",
4
4
  "license": "Apache 2.0",
5
5
  "description": "SAML 2.0 service",
6
6
  "main": "dist/index.js",
@@ -54,6 +54,8 @@
54
54
  "xmlbuilder": "15.1.1"
55
55
  },
56
56
  "devDependencies": {
57
+ "@types/express": "^4.17.13",
58
+ "@types/node": "^16.11.17",
57
59
  "@types/redis": "4.0.11",
58
60
  "@types/sinon": "10.0.6",
59
61
  "@types/tap": "15.0.5",
@@ -74,5 +76,9 @@
74
76
  "lint-staged": {
75
77
  "*.{js,ts}": "eslint --cache --fix",
76
78
  "*.{js,ts,css,md}": "prettier --write"
77
- }
79
+ },
80
+ "files": [
81
+ "dist",
82
+ "Dockerfile"
83
+ ]
78
84
  }
package/ nodemon.json DELETED
@@ -1,12 +0,0 @@
1
- {
2
- "restartable": "rs",
3
- "ignore": [".git", "node_modules/", "dist/", "coverage/"],
4
- "watch": ["src/"],
5
- "execMap": {
6
- "ts": "node -r ts-node/register"
7
- },
8
- "env": {
9
- "NODE_ENV": "development"
10
- },
11
- "ext": "js,json,ts"
12
- }
package/.dockerignore DELETED
@@ -1,2 +0,0 @@
1
- node_modules
2
- npm-debug.log
package/.eslintrc.js DELETED
@@ -1,18 +0,0 @@
1
- module.exports = {
2
- env: {
3
- es2021: true,
4
- node: true,
5
- },
6
- parserOptions: {
7
- ecmaVersion: 13,
8
- sourceType: 'module',
9
- },
10
- root: true,
11
- parser: '@typescript-eslint/parser',
12
- plugins: ['@typescript-eslint'],
13
- extends: [
14
- 'eslint:recommended',
15
- 'plugin:@typescript-eslint/recommended',
16
- 'prettier',
17
- ],
18
- };
@@ -1,27 +0,0 @@
1
- ---
2
- name: Bug report
3
- about: Report any issues with the platform
4
- title: ""
5
- labels: bug
6
- assignees: ""
7
- ---
8
-
9
- Found a bug? Please fill out the sections below. 👍
10
-
11
- ### Issue Summary
12
-
13
- A summary of the issue. This needs to be a clear detailed-rich summary.
14
-
15
- ### Steps to Reproduce
16
-
17
- 1. (for example) Went to ...
18
- 2. Clicked on...
19
- 3. ...
20
-
21
- Any other relevant information. For example, why do you consider this a bug and what did you expect to happen instead?
22
-
23
- ### Technical details
24
-
25
- - Browser version: You can use https://www.whatsmybrowser.org/ to find this out.
26
- - Node.js version
27
- - Anything else that you think could be an issue.
@@ -1,5 +0,0 @@
1
- blank_issues_enabled: false
2
- contact_links:
3
- - name: Questions
4
- url: https://github.com/boxyhq/jackson/discussions
5
- about: Ask a general question about the project on our GitHub Discussion page
@@ -1,43 +0,0 @@
1
- ---
2
- name: Feature request
3
- about: Suggest a feature or idea
4
- title: ""
5
- labels: enhancement
6
- assignees: ""
7
- ---
8
-
9
- > Please check if your Feature Request has not been already raised in the [Discussions Tab](https://github.com/boxyhq/jackson/discussions), as we would like to reduce duplicates. If it has been already raised, simply upvote it 🔼.
10
-
11
- ### Is your proposal related to a problem?
12
-
13
- <!--
14
- Provide a clear and concise description of what the problem is.
15
- For example, "I'm always frustrated when..."
16
- -->
17
-
18
- (Write your answer here.)
19
-
20
- ### Describe the solution you'd like
21
-
22
- <!--
23
- Provide a clear and concise description of what you want to happen.
24
- -->
25
-
26
- (Describe your proposed solution here.)
27
-
28
- ### Describe alternatives you've considered
29
-
30
- <!--
31
- Let us know about other solutions you've tried or researched.
32
- -->
33
-
34
- (Write your answer here.)
35
-
36
- ### Additional context
37
-
38
- <!--
39
- Is there anything else you can add about the proposal?
40
- You might want to link to related issues here, if you haven't already.
41
- -->
42
-
43
- (Write your answer here.)
@@ -1,31 +0,0 @@
1
- ## What does this PR do?
2
-
3
- <!-- Please include a summary of the change and which issue is fixed. Please also include relevant motivation and context. List any dependencies that are required for this change. -->
4
-
5
- Fixes # (issue)
6
-
7
- ## Type of change
8
-
9
- <!-- Please delete options that are not relevant. -->
10
-
11
- - [ ] Bug fix (non-breaking change which fixes an issue)
12
- - [ ] New feature (non-breaking change which adds functionality)
13
- - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
14
- - [ ] This change requires a documentation update
15
-
16
- ## How should this be tested?
17
-
18
- <!-- Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration -->
19
-
20
- - [ ] Test A
21
- - [ ] Test B
22
-
23
- ## Checklist:
24
-
25
- - [ ] My code follows the style guidelines of this project
26
- - [ ] I have performed a self-review of my own code and corrected any misspellings
27
- - [ ] I have commented my code, particularly in hard-to-understand areas
28
- - [ ] I have made corresponding changes to the documentation
29
- - [ ] My changes generate no new warnings
30
- - [ ] I have added tests that prove my fix is effective or that my feature works
31
- - [ ] New and existing unit tests pass locally with my changes
@@ -1,81 +0,0 @@
1
- on:
2
- push:
3
- branches:
4
- - main
5
- pull_request_target:
6
- types: [opened, synchronize, reopened]
7
-
8
- name: CodeSee Map
9
-
10
- jobs:
11
- test_map_action:
12
- runs-on: ubuntu-latest
13
- continue-on-error: true
14
- name: Run CodeSee Map Analysis
15
- steps:
16
- - name: checkout
17
- id: checkout
18
- uses: actions/checkout@v2
19
- with:
20
- repository: ${{ github.event.pull_request.head.repo.full_name }}
21
- ref: ${{ github.event.pull_request.head.ref }}
22
- fetch-depth: 0
23
-
24
- # codesee-detect-languages has an output with id languages.
25
- - name: Detect Languages
26
- id: detect-languages
27
- uses: Codesee-io/codesee-detect-languages-action@latest
28
-
29
- - name: Configure JDK 16
30
- uses: actions/setup-java@v2
31
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).java }}
32
- with:
33
- java-version: '16'
34
- distribution: 'zulu'
35
-
36
- # CodeSee Maps Go support uses a static binary so there's no setup step required.
37
-
38
- - name: Configure Node.js 14
39
- uses: actions/setup-node@v2
40
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).javascript }}
41
- with:
42
- node-version: '14'
43
-
44
- - name: Configure Python 3.x
45
- uses: actions/setup-python@v2
46
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).python }}
47
- with:
48
- python-version: '3.x'
49
- architecture: 'x64'
50
-
51
- - name: Configure Ruby '3.x'
52
- uses: ruby/setup-ruby@v1
53
- if: ${{ fromJSON(steps.detect-languages.outputs.languages).ruby }}
54
- with:
55
- ruby-version: '3.0'
56
-
57
- # CodeSee Maps Rust support uses a static binary so there's no setup step required.
58
-
59
- - name: Generate Map
60
- id: generate-map
61
- uses: Codesee-io/codesee-map-action@latest
62
- with:
63
- step: map
64
- github_ref: ${{ github.ref }}
65
- languages: ${{ steps.detect-languages.outputs.languages }}
66
-
67
- - name: Upload Map
68
- id: upload-map
69
- uses: Codesee-io/codesee-map-action@latest
70
- with:
71
- step: mapUpload
72
- api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
73
- github_ref: ${{ github.ref }}
74
-
75
- - name: Insights
76
- id: insights
77
- uses: Codesee-io/codesee-map-action@latest
78
- with:
79
- step: insights
80
- api_token: ${{ secrets.CODESEE_ARCH_DIAG_API_TOKEN }}
81
- github_ref: ${{ github.ref }}
@@ -1,123 +0,0 @@
1
- # This is a basic workflow to help you get started with Actions
2
-
3
- name: CI
4
-
5
- # Controls when the workflow will run
6
- on:
7
- # Triggers the workflow on push or pull request events but only for the main branch
8
- push:
9
- branches:
10
- - '*'
11
- pull_request:
12
- types: [opened, synchronize, reopened]
13
-
14
- # Allows you to run this workflow manually from the Actions tab
15
- workflow_dispatch:
16
-
17
- # A workflow run is made up of one or more jobs that can run sequentially or in parallel
18
- jobs:
19
- publish:
20
- runs-on: ubuntu-latest
21
-
22
- strategy:
23
- matrix:
24
- node-version: [16.x]
25
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
26
-
27
- services:
28
- postgres:
29
- image: postgres:13
30
- ports:
31
- - 5432:5432
32
- env:
33
- POSTGRES_PASSWORD: ""
34
- POSTGRES_HOST_AUTH_METHOD: "trust"
35
- # Set health checks to wait until postgres has started
36
- options: >-
37
- --health-cmd pg_isready
38
- --health-interval 10s
39
- --health-timeout 5s
40
- --health-retries 5
41
- redis:
42
- image: redis:6.2.5-alpine
43
- ports:
44
- - 6379:6379
45
- mongo:
46
- image: mongo:4.4.10
47
- ports:
48
- - 27017:27017
49
- mysql:
50
- image: mysql:5.7
51
- ports:
52
- - 3307:3306
53
- env:
54
- MYSQL_DATABASE: mysql
55
- MYSQL_ROOT_PASSWORD: mysql
56
- maria:
57
- image: mariadb:10.4.22
58
- ports:
59
- - 3306:3306
60
- env:
61
- MARIADB_DATABASE: mysql
62
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: "yes"
63
-
64
- steps:
65
- - uses: actions/checkout@v2
66
- - name: Use Node.js ${{ matrix.node-version }}
67
- uses: actions/setup-node@v2
68
- with:
69
- always-auth: true
70
- node-version: ${{ matrix.node-version }}
71
- registry-url: https://registry.npmjs.org
72
- scope: '@boxyhq'
73
- cache: 'npm'
74
- - run: npm ci
75
- - run: npm run test
76
- - run: |
77
- publishTag="latest"
78
- if [[ "$GITHUB_REF" == *\/release ]]
79
- then
80
- echo "Release branch"
81
- else
82
- echo "Dev branch"
83
- publishTag="beta"
84
- versionSuffixTag="-beta.${GITHUB_RUN_NUMBER}"
85
- sed "s/\(^[ ]*\"version\"\:[ ]*\".*\)\",/\1${versionSuffixTag}\",/" < package.json > package.json.new
86
- mv package.json.new package.json
87
- fi
88
- npm publish --tag $publishTag --access public
89
- env:
90
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
91
- build:
92
- needs: publish
93
- runs-on: ubuntu-latest
94
-
95
- steps:
96
- - name: Check Out Repo
97
- uses: actions/checkout@v2
98
-
99
- - name: Get short SHA
100
- id: slug
101
- run: echo "::set-output name=sha7::$(echo ${GITHUB_SHA} | cut -c1-7)"
102
-
103
- - name: Set up Docker Buildx
104
- id: buildx
105
- uses: docker/setup-buildx-action@v1
106
-
107
- - name: Login to Docker Hub
108
- uses: docker/login-action@v1
109
- with:
110
- username: ${{ secrets.DOCKER_HUB_USERNAME }}
111
- password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
112
-
113
- - name: Build and push
114
- id: docker_build
115
- uses: docker/build-push-action@v2
116
- with:
117
- context: ./
118
- file: ./Dockerfile
119
- push: true
120
- tags: ${{ github.repository }}:latest,${{ github.repository }}:${{ steps.slug.outputs.sha7 }}
121
-
122
- - name: Image digest
123
- run: echo ${{ steps.docker_build.outputs.digest }}
@@ -1,37 +0,0 @@
1
- # this file is a helper to run all the supported dbs locally, the data is ephemeral since no host volumes will be mounted
2
- version: "3.6"
3
- services:
4
- postgres:
5
- image: postgres:13
6
- ports:
7
- - "5432:5432"
8
- restart: always
9
- environment:
10
- POSTGRES_PASSWORD: ""
11
- POSTGRES_HOST_AUTH_METHOD: trust
12
- redis:
13
- image: redis:6.2.5-alpine
14
- ports:
15
- - "6379:6379"
16
- restart: always
17
- mongo:
18
- image: mongo:4.4.10
19
- ports:
20
- - "27017:27017"
21
- restart: always
22
- mysql:
23
- image: mysql:5.7
24
- ports:
25
- - "3307:3306"
26
- restart: always
27
- environment:
28
- MYSQL_DATABASE: mysql
29
- MYSQL_ROOT_PASSWORD: mysql
30
- maria:
31
- image: mariadb:10.4.22
32
- ports:
33
- - "3306:3306"
34
- restart: always
35
- environment:
36
- MARIADB_DATABASE: mysql
37
- MARIADB_ALLOW_EMPTY_ROOT_PASSWORD: "yes"
package/map.js DELETED
@@ -1 +0,0 @@
1
- module.exports = (test) => test.replace(/\.test\.js$/, '.js');
@@ -1,4 +0,0 @@
1
- module.exports = {
2
- singleQuote: true,
3
- trailingComma: 'es5',
4
- };
@@ -1,225 +0,0 @@
1
- import crypto from 'crypto';
2
- import { IdPConfig, ISAMLConfig, OAuth, Storable } from 'saml-jackson';
3
- import * as dbutils from '../db/utils';
4
- import saml from '../saml/saml';
5
- import { JacksonError } from './error';
6
- import { IndexNames } from './utils';
7
- import x509 from '../saml/x509';
8
-
9
- export class SAMLConfig implements ISAMLConfig {
10
- private configStore: Storable;
11
-
12
- constructor({ configStore }) {
13
- this.configStore = configStore;
14
- }
15
-
16
- private _validateIdPConfig(body: IdPConfig): void {
17
- const { rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } =
18
- body;
19
-
20
- if (!rawMetadata) {
21
- throw new JacksonError('Please provide rawMetadata', 400);
22
- }
23
-
24
- if (!defaultRedirectUrl) {
25
- throw new JacksonError('Please provide a defaultRedirectUrl', 400);
26
- }
27
-
28
- if (!redirectUrl) {
29
- throw new JacksonError('Please provide redirectUrl', 400);
30
- }
31
-
32
- if (!tenant) {
33
- throw new JacksonError('Please provide tenant', 400);
34
- }
35
-
36
- if (!product) {
37
- throw new JacksonError('Please provide product', 400);
38
- }
39
- }
40
-
41
- public async create(body: IdPConfig): Promise<OAuth> {
42
- const { rawMetadata, defaultRedirectUrl, redirectUrl, tenant, product } =
43
- body;
44
-
45
- this._validateIdPConfig(body);
46
-
47
- const idpMetadata = await saml.parseMetadataAsync(rawMetadata);
48
-
49
- // extract provider
50
- let providerName = extractHostName(idpMetadata.entityID);
51
- if (!providerName) {
52
- providerName = extractHostName(
53
- idpMetadata.sso.redirectUrl || idpMetadata.sso.postUrl
54
- );
55
- }
56
-
57
- idpMetadata.provider = providerName ? providerName : 'Unknown';
58
-
59
- let clientID = dbutils.keyDigest(
60
- dbutils.keyFromParts(tenant, product, idpMetadata.entityID)
61
- );
62
-
63
- let clientSecret;
64
-
65
- let exists = await this.configStore.get(clientID);
66
-
67
- if (exists) {
68
- clientSecret = exists.clientSecret;
69
- } else {
70
- clientSecret = crypto.randomBytes(24).toString('hex');
71
- }
72
-
73
- const certs = await x509.generate();
74
-
75
- if (!certs) {
76
- throw new Error('Error generating x59 certs');
77
- }
78
-
79
- await this.configStore.put(
80
- clientID,
81
- {
82
- idpMetadata,
83
- defaultRedirectUrl,
84
- redirectUrl: JSON.parse(redirectUrl), // redirectUrl is a stringified array
85
- tenant,
86
- product,
87
- clientID,
88
- clientSecret,
89
- certs,
90
- },
91
- {
92
- // secondary index on entityID
93
- name: IndexNames.EntityID,
94
- value: idpMetadata.entityID,
95
- },
96
- {
97
- // secondary index on tenant + product
98
- name: IndexNames.TenantProduct,
99
- value: dbutils.keyFromParts(tenant, product),
100
- }
101
- );
102
-
103
- return {
104
- client_id: clientID,
105
- client_secret: clientSecret,
106
- provider: idpMetadata.provider,
107
- };
108
- }
109
-
110
- public async get(body: {
111
- clientID: string;
112
- tenant: string;
113
- product: string;
114
- }): Promise<Partial<OAuth>> {
115
- const { clientID, tenant, product } = body;
116
-
117
- if (clientID) {
118
- const samlConfig = await this.configStore.get(clientID);
119
-
120
- return samlConfig ? { provider: samlConfig.idpMetadata.provider } : {};
121
- }
122
-
123
- if (tenant && product) {
124
- const samlConfigs = await this.configStore.getByIndex({
125
- name: IndexNames.TenantProduct,
126
- value: dbutils.keyFromParts(tenant, product),
127
- });
128
-
129
- if (!samlConfigs || !samlConfigs.length) {
130
- return {};
131
- }
132
-
133
- return { provider: samlConfigs[0].idpMetadata.provider };
134
- }
135
-
136
- throw new JacksonError(
137
- 'Please provide `clientID` or `tenant` and `product`.',
138
- 400
139
- );
140
- }
141
-
142
- public async delete(body: {
143
- clientID: string;
144
- clientSecret: string;
145
- tenant: string;
146
- product: string;
147
- }): Promise<void> {
148
- const { clientID, clientSecret, tenant, product } = body;
149
-
150
- if (clientID && clientSecret) {
151
- const samlConfig = await this.configStore.get(clientID);
152
-
153
- if (!samlConfig) {
154
- return;
155
- }
156
-
157
- if (samlConfig.clientSecret === clientSecret) {
158
- await this.configStore.delete(clientID);
159
- } else {
160
- throw new JacksonError('clientSecret mismatch.', 400);
161
- }
162
-
163
- return;
164
- }
165
-
166
- if (tenant && product) {
167
- const samlConfigs = await this.configStore.getByIndex({
168
- name: IndexNames.TenantProduct,
169
- value: dbutils.keyFromParts(tenant, product),
170
- });
171
-
172
- if (!samlConfigs || !samlConfigs.length) {
173
- return;
174
- }
175
-
176
- for (const conf of samlConfigs) {
177
- await this.configStore.delete(conf.clientID);
178
- }
179
-
180
- return;
181
- }
182
-
183
- throw new JacksonError(
184
- 'Please provide `clientID` and `clientSecret` or `tenant` and `product`.',
185
- 400
186
- );
187
- }
188
-
189
- // Ensure backward compatibility
190
-
191
- async config(body: IdPConfig): Promise<OAuth> {
192
- return this.create(body);
193
- }
194
-
195
- async getConfig(body: {
196
- clientID: string;
197
- tenant: string;
198
- product: string;
199
- }): Promise<Partial<OAuth>> {
200
- return this.get(body);
201
- }
202
-
203
- async deleteConfig(body: {
204
- clientID: string;
205
- clientSecret: string;
206
- tenant: string;
207
- product: string;
208
- }): Promise<void> {
209
- return this.delete(body);
210
- }
211
- }
212
-
213
- const extractHostName = (url: string): string | null => {
214
- try {
215
- const pUrl = new URL(url);
216
-
217
- if (pUrl.hostname.startsWith('www.')) {
218
- return pUrl.hostname.substring(4);
219
- }
220
-
221
- return pUrl.hostname;
222
- } catch (err) {
223
- return null;
224
- }
225
- };
@@ -1,13 +0,0 @@
1
- export class JacksonError extends Error {
2
- public name: string;
3
- public statusCode: number;
4
-
5
- constructor(message: string, statusCode: number = 500) {
6
- super(message);
7
-
8
- this.name = this.constructor.name;
9
- this.statusCode = statusCode;
10
-
11
- Error.captureStackTrace(this, this.constructor);
12
- }
13
- }
@@ -1,22 +0,0 @@
1
- export const redirect = (
2
- redirectUrl: string,
3
- redirectUrls: string[]
4
- ): boolean => {
5
- const url: URL = new URL(redirectUrl);
6
-
7
- for (const idx in redirectUrls) {
8
- const rUrl: URL = new URL(redirectUrls[idx]);
9
-
10
- // TODO: Check pathname, for now pathname is ignored
11
-
12
- if (
13
- rUrl.protocol === url.protocol &&
14
- rUrl.hostname === url.hostname &&
15
- rUrl.port === url.port
16
- ) {
17
- return true;
18
- }
19
- }
20
-
21
- return false;
22
- };
@@ -1,11 +0,0 @@
1
- import crypto from 'crypto';
2
-
3
- export const transformBase64 = (input: string): string => {
4
- return input.replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_');
5
- };
6
-
7
- export const encode = (code_challenge: string): string => {
8
- return transformBase64(
9
- crypto.createHash('sha256').update(code_challenge).digest('base64')
10
- );
11
- };