@sasjs/adapter 3.10.8 → 3.10.11

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.
@@ -0,0 +1,3 @@
1
+ export declare class InvalidSASjsCsrfError extends Error {
2
+ constructor();
3
+ }
@@ -1,20 +1,21 @@
1
+ export * from './appendExtraResponseAttributes';
1
2
  export * from './asyncForEach';
2
3
  export * from './compareTimestamps';
3
4
  export * from './convertToCsv';
4
5
  export * from './createAxiosInstance';
5
6
  export * from './delay';
7
+ export * from './fetchLogByChunks';
8
+ export * from './getValidJson';
6
9
  export * from './isNode';
7
10
  export * from './isRelativePath';
8
11
  export * from './isUri';
9
12
  export * from './isUrl';
10
13
  export * from './needsRetry';
11
14
  export * from './parseGeneratedCode';
12
- export * from './parseSourceCode';
13
15
  export * from './parseSasViyaLog';
16
+ export * from './parseSourceCode';
17
+ export * from './parseViyaDebugResponse';
18
+ export * from './parseWeboutResponse';
14
19
  export * from './serialize';
15
20
  export * from './splitChunks';
16
- export * from './parseWeboutResponse';
17
- export * from './fetchLogByChunks';
18
- export * from './getValidJson';
19
- export * from './parseViyaDebugResponse';
20
- export * from './appendExtraResponseAttributes';
21
+ export * from './validateInput';
@@ -0,0 +1,14 @@
1
+ export declare const MORE_INFO = "For more info see https://sasjs.io/sasjs-adapter/#request-response";
2
+ export declare const INVALID_TABLE_STRUCTURE: string;
3
+ /**
4
+ * This function validates the input data structure and table naming convention
5
+ *
6
+ * @param data A json object that contains one or more tables, it can also be null
7
+ * @returns An object which contains two attributes: 1) status: boolean, 2) msg: string
8
+ */
9
+ export declare const validateInput: (data: {
10
+ [key: string]: any;
11
+ } | null) => {
12
+ status: boolean;
13
+ msg: string;
14
+ };
package/package.json CHANGED
@@ -87,5 +87,5 @@
87
87
  "https": "1.0.0",
88
88
  "tough-cookie": "4.0.0"
89
89
  },
90
- "version": "3.10.8"
90
+ "version": "3.10.11"
91
91
  }
package/src/SASjs.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { compareTimestamps, asyncForEach } from './utils'
1
+ import { compareTimestamps, asyncForEach, validateInput } from './utils'
2
2
  import {
3
3
  SASjsConfig,
4
4
  UploadFile,
@@ -686,7 +686,7 @@ export default class SASjs {
686
686
  ...config
687
687
  }
688
688
 
689
- const validationResult = this.validateInput(data)
689
+ const validationResult = validateInput(data)
690
690
 
691
691
  // status is true if the data passes validation checks above
692
692
  if (validationResult.status) {
@@ -748,74 +748,6 @@ export default class SASjs {
748
748
  }
749
749
  }
750
750
 
751
- /**
752
- * This function validates the input data structure and table naming convention
753
- *
754
- * @param data A json object that contains one or more tables, it can also be null
755
- * @returns An object which contains two attributes: 1) status: boolean, 2) msg: string
756
- */
757
- private validateInput(data: { [key: string]: any } | null): {
758
- status: boolean
759
- msg: string
760
- } {
761
- if (data === null) return { status: true, msg: '' }
762
-
763
- const isSasFormatsTable = (key: string) =>
764
- key.match(/^\$.*/) && Object.keys(data).includes(key.replace(/^\$/, ''))
765
-
766
- for (const key in data) {
767
- if (!key.match(/^[a-zA-Z_]/) && !isSasFormatsTable(key)) {
768
- return {
769
- status: false,
770
- msg: 'First letter of table should be alphabet or underscore.'
771
- }
772
- }
773
-
774
- if (!key.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/) && !isSasFormatsTable(key)) {
775
- return { status: false, msg: 'Table name should be alphanumeric.' }
776
- }
777
-
778
- if (key.length > 32) {
779
- return {
780
- status: false,
781
- msg: 'Maximum length for table name could be 32 characters.'
782
- }
783
- }
784
-
785
- if (this.getType(data[key]) !== 'Array' && !isSasFormatsTable(key)) {
786
- return {
787
- status: false,
788
- msg: 'Parameter data contains invalid table structure.'
789
- }
790
- }
791
-
792
- for (let i = 0; i < data[key].length; i++) {
793
- if (this.getType(data[key][i]) !== 'object') {
794
- return {
795
- status: false,
796
- msg: `Table ${key} contains invalid structure.`
797
- }
798
- }
799
- }
800
- }
801
-
802
- return { status: true, msg: '' }
803
- }
804
-
805
- /**
806
- * this function returns the type of variable
807
- *
808
- * @param data it could be anything, like string, array, object etc.
809
- * @returns a string which tells the type of input parameter
810
- */
811
- private getType(data: any): string {
812
- if (Array.isArray(data)) {
813
- return 'Array'
814
- } else {
815
- return typeof data
816
- }
817
- }
818
-
819
751
  /**
820
752
  * Creates the folders and services at the given location `appLoc` on the given server `serverUrl`.
821
753
  * @param serviceJson - the JSON specifying the folders and services to be created.
@@ -223,9 +223,17 @@ export class AuthManager {
223
223
 
224
224
  private async getNewLoginForm() {
225
225
  if (this.serverType === ServerType.Sasjs) {
226
- // server will be sending CSRF cookie,
226
+ // server will be sending CSRF token in response,
227
+ // need to save in cookie so that,
227
228
  // http client will use it automatically
228
- return this.requestClient.get('/', undefined)
229
+ return this.requestClient.get('/', undefined).then(({ result }) => {
230
+ const cookie =
231
+ /<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/.exec(
232
+ result as string
233
+ )?.[1]
234
+
235
+ if (cookie) document.cookie = cookie
236
+ })
229
237
  }
230
238
 
231
239
  const { result: formResponse } = await this.requestClient.get<string>(
@@ -19,7 +19,7 @@ import {
19
19
  parseSourceCode,
20
20
  createAxiosInstance
21
21
  } from '../utils'
22
- import { InvalidCsrfError } from '../types/errors/InvalidCsrfError'
22
+ import { InvalidSASjsCsrfError } from '../types/errors/InvalidSASjsCsrfError'
23
23
 
24
24
  export interface HttpClient {
25
25
  get<T>(
@@ -499,12 +499,20 @@ export class RequestClient implements HttpClient {
499
499
  throw e
500
500
  }
501
501
 
502
- if (e instanceof InvalidCsrfError) {
503
- // Fetching root will inject CSRF token in cookie
502
+ if (e instanceof InvalidSASjsCsrfError) {
503
+ // Fetching root and creating CSRF cookie
504
504
  await this.httpClient
505
505
  .get('/', {
506
506
  withCredentials: true
507
507
  })
508
+ .then((response) => {
509
+ const cookie =
510
+ /<script>document.cookie = '(XSRF-TOKEN=.*; Max-Age=86400; SameSite=Strict; Path=\/;)'<\/script>/.exec(
511
+ response.data
512
+ )?.[1]
513
+
514
+ if (cookie) document.cookie = cookie
515
+ })
508
516
  .catch((err) => {
509
517
  throw prefixMessage(err, 'Error while re-fetching CSRF token.')
510
518
  })
@@ -611,8 +619,11 @@ export const throwIfError = (response: AxiosResponse) => {
611
619
  throw new LoginRequiredError(response.data)
612
620
  }
613
621
 
614
- if (response.data.toLowerCase() === 'invalid csrf token!') {
615
- throw new InvalidCsrfError()
622
+ if (
623
+ typeof response.data === 'string' &&
624
+ response.data.toLowerCase() === 'invalid csrf token!'
625
+ ) {
626
+ throw new InvalidSASjsCsrfError()
616
627
  }
617
628
  break
618
629
  case 401:
@@ -0,0 +1,9 @@
1
+ export class InvalidSASjsCsrfError extends Error {
2
+ constructor() {
3
+ const message = 'Invalid CSRF token!'
4
+
5
+ super(`Auth error: ${message}`)
6
+ this.name = 'InvalidSASjsCsrfError'
7
+ Object.setPrototypeOf(this, InvalidSASjsCsrfError.prototype)
8
+ }
9
+ }
@@ -1,20 +1,21 @@
1
+ export * from './appendExtraResponseAttributes'
1
2
  export * from './asyncForEach'
2
3
  export * from './compareTimestamps'
3
4
  export * from './convertToCsv'
4
5
  export * from './createAxiosInstance'
5
6
  export * from './delay'
7
+ export * from './fetchLogByChunks'
8
+ export * from './getValidJson'
6
9
  export * from './isNode'
7
10
  export * from './isRelativePath'
8
11
  export * from './isUri'
9
12
  export * from './isUrl'
10
13
  export * from './needsRetry'
11
14
  export * from './parseGeneratedCode'
12
- export * from './parseSourceCode'
13
15
  export * from './parseSasViyaLog'
16
+ export * from './parseSourceCode'
17
+ export * from './parseViyaDebugResponse'
18
+ export * from './parseWeboutResponse'
14
19
  export * from './serialize'
15
20
  export * from './splitChunks'
16
- export * from './parseWeboutResponse'
17
- export * from './fetchLogByChunks'
18
- export * from './getValidJson'
19
- export * from './parseViyaDebugResponse'
20
- export * from './appendExtraResponseAttributes'
21
+ export * from './validateInput'
@@ -0,0 +1,90 @@
1
+ export const MORE_INFO =
2
+ 'For more info see https://sasjs.io/sasjs-adapter/#request-response'
3
+ export const INVALID_TABLE_STRUCTURE = `Parameter data contains invalid table structure. ${MORE_INFO}`
4
+
5
+ /**
6
+ * This function validates the input data structure and table naming convention
7
+ *
8
+ * @param data A json object that contains one or more tables, it can also be null
9
+ * @returns An object which contains two attributes: 1) status: boolean, 2) msg: string
10
+ */
11
+ export const validateInput = (
12
+ data: { [key: string]: any } | null
13
+ ): {
14
+ status: boolean
15
+ msg: string
16
+ } => {
17
+ if (data === null) return { status: true, msg: '' }
18
+
19
+ if (getType(data) !== 'object') {
20
+ return {
21
+ status: false,
22
+ msg: INVALID_TABLE_STRUCTURE
23
+ }
24
+ }
25
+
26
+ const isSasFormatsTable = (key: string) =>
27
+ key.match(/^\$.*/) && Object.keys(data).includes(key.replace(/^\$/, ''))
28
+
29
+ for (const key in data) {
30
+ if (!key.match(/^[a-zA-Z_]/) && !isSasFormatsTable(key)) {
31
+ return {
32
+ status: false,
33
+ msg: 'First letter of table should be alphabet or underscore.'
34
+ }
35
+ }
36
+
37
+ if (!key.match(/^[a-zA-Z_][a-zA-Z0-9_]*$/) && !isSasFormatsTable(key)) {
38
+ return { status: false, msg: 'Table name should be alphanumeric.' }
39
+ }
40
+
41
+ if (key.length > 32) {
42
+ return {
43
+ status: false,
44
+ msg: 'Maximum length for table name could be 32 characters.'
45
+ }
46
+ }
47
+
48
+ if (getType(data[key]) !== 'Array' && !isSasFormatsTable(key)) {
49
+ return {
50
+ status: false,
51
+ msg: INVALID_TABLE_STRUCTURE
52
+ }
53
+ }
54
+
55
+ for (const item of data[key]) {
56
+ if (getType(item) !== 'object') {
57
+ return {
58
+ status: false,
59
+ msg: `Table ${key} contains invalid structure. ${MORE_INFO}`
60
+ }
61
+ } else {
62
+ const attributes = Object.keys(item)
63
+ for (const attribute of attributes) {
64
+ if (item[attribute] === undefined) {
65
+ return {
66
+ status: false,
67
+ msg: `A row in table ${key} contains invalid value. Can't assign undefined to ${attribute}.`
68
+ }
69
+ }
70
+ }
71
+ }
72
+ }
73
+ }
74
+
75
+ return { status: true, msg: '' }
76
+ }
77
+
78
+ /**
79
+ * this function returns the type of variable
80
+ *
81
+ * @param data it could be anything, like string, array, object etc.
82
+ * @returns a string which tells the type of input parameter
83
+ */
84
+ const getType = (data: any): string => {
85
+ if (Array.isArray(data)) {
86
+ return 'Array'
87
+ } else {
88
+ return typeof data
89
+ }
90
+ }
@@ -0,0 +1,3 @@
1
+ export declare class InvalidSASjsCsrfError extends Error {
2
+ constructor();
3
+ }
package/utils/index.d.ts CHANGED
@@ -1,20 +1,21 @@
1
+ export * from './appendExtraResponseAttributes';
1
2
  export * from './asyncForEach';
2
3
  export * from './compareTimestamps';
3
4
  export * from './convertToCsv';
4
5
  export * from './createAxiosInstance';
5
6
  export * from './delay';
7
+ export * from './fetchLogByChunks';
8
+ export * from './getValidJson';
6
9
  export * from './isNode';
7
10
  export * from './isRelativePath';
8
11
  export * from './isUri';
9
12
  export * from './isUrl';
10
13
  export * from './needsRetry';
11
14
  export * from './parseGeneratedCode';
12
- export * from './parseSourceCode';
13
15
  export * from './parseSasViyaLog';
16
+ export * from './parseSourceCode';
17
+ export * from './parseViyaDebugResponse';
18
+ export * from './parseWeboutResponse';
14
19
  export * from './serialize';
15
20
  export * from './splitChunks';
16
- export * from './parseWeboutResponse';
17
- export * from './fetchLogByChunks';
18
- export * from './getValidJson';
19
- export * from './parseViyaDebugResponse';
20
- export * from './appendExtraResponseAttributes';
21
+ export * from './validateInput';
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,14 @@
1
+ export declare const MORE_INFO = "For more info see https://sasjs.io/sasjs-adapter/#request-response";
2
+ export declare const INVALID_TABLE_STRUCTURE: string;
3
+ /**
4
+ * This function validates the input data structure and table naming convention
5
+ *
6
+ * @param data A json object that contains one or more tables, it can also be null
7
+ * @returns An object which contains two attributes: 1) status: boolean, 2) msg: string
8
+ */
9
+ export declare const validateInput: (data: {
10
+ [key: string]: any;
11
+ } | null) => {
12
+ status: boolean;
13
+ msg: string;
14
+ };
@@ -1,3 +0,0 @@
1
- export declare class InvalidCsrfError extends Error {
2
- constructor();
3
- }
@@ -1,9 +0,0 @@
1
- export class InvalidCsrfError extends Error {
2
- constructor() {
3
- const message = 'Invalid CSRF token!'
4
-
5
- super(`Auth error: ${message}`)
6
- this.name = 'InvalidCsrfError'
7
- Object.setPrototypeOf(this, InvalidCsrfError.prototype)
8
- }
9
- }
@@ -1,3 +0,0 @@
1
- export declare class InvalidCsrfError extends Error {
2
- constructor();
3
- }