* feat(auth): init auth package & collection * feat(auth): register * feat(auth): use authenticator * feat(auth): mapRoles * feat(auth): refactor * feat(auth): base auth class * feat(auth): add plugin * chore(auth): test * chore(auth): add test cases * feat(auth): authenticators pane * chore(auth): custom hook useAuthTypes * feat(auth): authenticator pane * chore(auth): store options schema using context * feat(auth): signInPage provider * feat(auth): signUpPage provider * chore(auth): solve build errors * chore(auth): add dependency * chore(auth): remove dependency cycles * chore(auth): add plugin-auth to preset * chore(auth): fix test * feat(auth): authenticator enable status * fix(test): fix test using new authentication * feat(auth): migration, set up basic auth * chore(auth): can set options ui by component * fix(test): workflow manunal.test * fix(test): typo * feat(auth): support multi-language * chore(auth): imporve code * chore(auth): hide button if no configuration * chore(auth): readme * chore(auth): remove allowSignup prop * chore(auth): move configure pane to edit form * fix(auth): jwt options bug * feat(auth): init sms-auth * chore(auth): at least authenticator required * chore(auth): add test * feat(auth): support sms auth * fix(auth): fix test * chore(auth): move findOrCreateUser to AuthModel * chore(auth): history compatible processing * feat(auth): support SAML auth * chore(auth): saml auth list * chore(saml-auth): improve ui * Merge branch 'main' into feat/authentication * chore(auth): improve code * fix(saml-auth): fix bug * fix(saml-auth): fix saml options * chore(saml-auth): compatible processing && ut * fix(auth): signin page bug * chore(auth): saml compatible processing * feat(auth): oidc-auth * fix(oidc-auth): bug * fix(oidc-auth): bug * fix(auth): fix test * chore(auth): filter enabled authenticator * chore(oidc): add field map * chore(auth): update readme * docs(auth): create sms-auth readme * feat(auth): allow signup config * test(auth): fix test * feat(auth): allow saml and oidc use http * chore(oidc-auth): extends timeout * docs(auth): update readme * feat(auth): support sort * docs(saml): update readme * feat(auth): support sort all authenticator * Merge branch 'main' into feat/authentication * Merge branch 'main' into feat/authentication * feat: improve code * docs(auth): add doc * Merge branch 'main' into feat/authentication * chore: update yarn.lock * feat: improve code * chore(acl): write role to acl if it exists in database and not found … (#2001) * chore(acl): write role to acl if it exists in database and not found in acl * fix: test * fix: eager load with nested association (#2002) * chore: upgrade vitest * chore: edit * refactor: auth class * fix: set options * chore(acl): write role to acl if it exists in database and not found … (#2001) * chore(acl): write role to acl if it exists in database and not found in acl * fix: test * fix: eager load with nested association (#2002) * chore: upgrade vitest * chore: add migrations * test: fix api-client test * chore: add sms-auth * feat: avoid no permission after auth type disabled * fix: translation --------- Co-authored-by: chenos <chenlinxh@gmail.com>
		
			
				
	
	
		
			205 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			205 lines
		
	
	
		
			5.3 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { Database, mockDatabase } from '@nocobase/database';
 | |
| import Application, { ApplicationOptions, PluginManager } from '@nocobase/server';
 | |
| import jwt from 'jsonwebtoken';
 | |
| import qs from 'qs';
 | |
| import supertest, { SuperAgentTest } from 'supertest';
 | |
| 
 | |
| interface ActionParams {
 | |
|   filterByTk?: any;
 | |
|   fields?: string[];
 | |
|   filter?: any;
 | |
|   sort?: string[];
 | |
|   page?: number;
 | |
|   pageSize?: number;
 | |
|   values?: any;
 | |
|   /**
 | |
|    * @deprecated
 | |
|    */
 | |
|   resourceName?: string;
 | |
|   /**
 | |
|    * @deprecated
 | |
|    */
 | |
|   resourceIndex?: string;
 | |
|   /**
 | |
|    * @deprecated
 | |
|    */
 | |
|   associatedName?: string;
 | |
|   /**
 | |
|    * @deprecated
 | |
|    */
 | |
|   associatedIndex?: string;
 | |
| 
 | |
|   [key: string]: any;
 | |
| }
 | |
| 
 | |
| interface SortActionParams {
 | |
|   resourceName?: string;
 | |
|   resourceIndex?: any;
 | |
|   associatedName?: string;
 | |
|   associatedIndex?: any;
 | |
|   sourceId?: any;
 | |
|   targetId?: any;
 | |
|   sortField?: string;
 | |
|   method?: string;
 | |
|   target?: any;
 | |
|   sticky?: boolean;
 | |
| 
 | |
|   [key: string]: any;
 | |
| }
 | |
| 
 | |
| interface Resource {
 | |
|   get: (params?: ActionParams) => Promise<supertest.Response>;
 | |
|   list: (params?: ActionParams) => Promise<supertest.Response>;
 | |
|   create: (params?: ActionParams) => Promise<supertest.Response>;
 | |
|   update: (params?: ActionParams) => Promise<supertest.Response>;
 | |
|   destroy: (params?: ActionParams) => Promise<supertest.Response>;
 | |
|   sort: (params?: SortActionParams) => Promise<supertest.Response>;
 | |
| 
 | |
|   [name: string]: (params?: ActionParams) => Promise<supertest.Response>;
 | |
| }
 | |
| 
 | |
| export class MockServer extends Application {
 | |
|   async loadAndInstall(options: any = {}) {
 | |
|     await this.load({ method: 'install' });
 | |
| 
 | |
|     if (options.afterLoad) {
 | |
|       await options.afterLoad(this);
 | |
|     }
 | |
| 
 | |
|     await this.install({
 | |
|       ...options,
 | |
|       sync: {
 | |
|         force: false,
 | |
|         alter: {
 | |
|           drop: false,
 | |
|         },
 | |
|       },
 | |
|     });
 | |
|   }
 | |
| 
 | |
|   async cleanDb() {
 | |
|     await this.db.clean({ drop: true });
 | |
|   }
 | |
| 
 | |
|   agent(): SuperAgentTest & {
 | |
|     login: (user: any) => SuperAgentTest;
 | |
|     loginUsingId: (userId: number) => SuperAgentTest;
 | |
|     resource: (name: string, resourceOf?: any) => Resource;
 | |
|   } {
 | |
|     const agent = supertest.agent(this.appManager.callback());
 | |
|     const prefix = this.resourcer.options.prefix;
 | |
|     const proxy = new Proxy(agent, {
 | |
|       get(target, method: string, receiver) {
 | |
|         if (['login', 'loginUsingId'].includes(method)) {
 | |
|           return (userOrId: any) => {
 | |
|             return proxy
 | |
|               .auth(
 | |
|                 jwt.sign(
 | |
|                   {
 | |
|                     userId: typeof userOrId === 'number' ? userOrId : userOrId?.id,
 | |
|                   },
 | |
|                   process.env.APP_KEY,
 | |
|                 ),
 | |
|                 { type: 'bearer' },
 | |
|               )
 | |
|               .set('X-Authenticator', 'basic');
 | |
|           };
 | |
|         }
 | |
|         if (method === 'resource') {
 | |
|           return (name: string, resourceOf?: any) => {
 | |
|             const keys = name.split('.');
 | |
|             const proxy = new Proxy(
 | |
|               {},
 | |
|               {
 | |
|                 get(target, method: string, receiver) {
 | |
|                   return (params: ActionParams = {}) => {
 | |
|                     let { filterByTk, values = {}, file, ...restParams } = params;
 | |
|                     if (params.associatedIndex) {
 | |
|                       resourceOf = params.associatedIndex;
 | |
|                     }
 | |
|                     if (params.resourceIndex) {
 | |
|                       filterByTk = params.resourceIndex;
 | |
|                     }
 | |
|                     let url = prefix || '';
 | |
|                     if (keys.length > 1) {
 | |
|                       url += `/${keys[0]}/${resourceOf}/${keys[1]}`;
 | |
|                     } else {
 | |
|                       url += `/${name}`;
 | |
|                     }
 | |
|                     url += `:${method as string}`;
 | |
|                     if (filterByTk) {
 | |
|                       url += `/${filterByTk}`;
 | |
|                     }
 | |
| 
 | |
|                     const queryString = qs.stringify(restParams, { arrayFormat: 'brackets' });
 | |
| 
 | |
|                     let request;
 | |
| 
 | |
|                     switch (method) {
 | |
|                       case 'list':
 | |
|                       case 'get':
 | |
|                         request = agent.get(`${url}?${queryString}`);
 | |
|                         break;
 | |
|                       default:
 | |
|                         request = agent.post(`${url}?${queryString}`);
 | |
|                         break;
 | |
|                     }
 | |
| 
 | |
|                     return file ? request.attach('file', file).field(values) : request.send(values);
 | |
|                   };
 | |
|                 },
 | |
|               },
 | |
|             );
 | |
|             return proxy;
 | |
|           };
 | |
|         }
 | |
|         return agent[method];
 | |
|       },
 | |
|     });
 | |
|     return proxy as any;
 | |
|   }
 | |
| }
 | |
| 
 | |
| export function mockServer(options: ApplicationOptions = {}) {
 | |
|   if (typeof TextEncoder === 'undefined') {
 | |
|     global.TextEncoder = require('util').TextEncoder;
 | |
|   }
 | |
| 
 | |
|   if (typeof TextDecoder === 'undefined') {
 | |
|     global.TextDecoder = require('util').TextDecoder;
 | |
|   }
 | |
| 
 | |
|   // @ts-ignore
 | |
|   if (!PluginManager.findPackagePatched) {
 | |
|     PluginManager.getPackageJson = () => {
 | |
|       return {
 | |
|         version: '0.0.0',
 | |
|       };
 | |
|     };
 | |
| 
 | |
|     // @ts-ignore
 | |
|     PluginManager.findPackagePatched = true;
 | |
|   }
 | |
| 
 | |
|   let database;
 | |
|   if (options?.database instanceof Database) {
 | |
|     database = options.database;
 | |
|   } else {
 | |
|     database = mockDatabase(<any>options?.database || {});
 | |
|   }
 | |
| 
 | |
|   const app = new MockServer({
 | |
|     acl: false,
 | |
|     ...options,
 | |
|     database,
 | |
|   });
 | |
| 
 | |
|   app.pm.generateClientFile = async () => {};
 | |
| 
 | |
|   return app;
 | |
| }
 | |
| 
 | |
| export function createMockServer() {}
 | |
| 
 | |
| export default mockServer;
 |