chore: merge master

This commit is contained in:
Alex Grozav 2023-07-27 13:16:19 +03:00
commit efdab3e14d
46 changed files with 276 additions and 284 deletions

View file

@ -1,3 +1,110 @@
# [1.1.0](https://github.com/n8n-io/n8n/compare/n8n@1.0.1...n8n@1.1.0) (2023-07-26)
### Bug Fixes
* Add missing indices on sqlite ([#6673](https://github.com/n8n-io/n8n/issues/6673)) ([b1838f7](https://github.com/n8n-io/n8n/commit/b1838f7fab3e6d2983fa4d2ba1a480c79f8fe2c5))
* **API:** Do not add starting node on workflow creation ([#6686](https://github.com/n8n-io/n8n/issues/6686)) ([92192fb](https://github.com/n8n-io/n8n/commit/92192fbd6108a71fca591e5284269239d4347621))
* **API:** Fix issue with workflow setting not supporting newer nanoids ([#6699](https://github.com/n8n-io/n8n/issues/6699)) ([c7e1013](https://github.com/n8n-io/n8n/commit/c7e10130d694347982f50bc0ad1024101e27beea))
* **AwsS3 Node:** Fix issue if bucket name contains a '.' ([#6542](https://github.com/n8n-io/n8n/issues/6542)) ([540d32d](https://github.com/n8n-io/n8n/commit/540d32dee4b8927199e047c77acf516d5b824bc3))
* **Brevo Node:** Rename SendInBlue node to Brevo node ([#6521](https://github.com/n8n-io/n8n/issues/6521)) ([e63b398](https://github.com/n8n-io/n8n/commit/e63b3982d200ade34461b9159eb1e988f494c025))
* **Code Node:** Install python modules always in a user-writable folder ([#6568](https://github.com/n8n-io/n8n/issues/6568)) ([bf35124](https://github.com/n8n-io/n8n/commit/bf351243dfa69095699596e8828904fda025d45c))
* **core:** Add empty credential value marker to show empty pw field ([#6532](https://github.com/n8n-io/n8n/issues/6532)) ([9294e2d](https://github.com/n8n-io/n8n/commit/9294e2da3c7c99c2099f5865e610fa7217bf06be))
* **core:** Deleting manual executions should defer deleting binary data ([#6680](https://github.com/n8n-io/n8n/issues/6680)) ([462a674](https://github.com/n8n-io/n8n/commit/462a674d1759dc5ae9849daa48cc8c4130dd030e))
* **core:** Filter out workflows that failed to activate on startup ([#6676](https://github.com/n8n-io/n8n/issues/6676)) ([667c15d](https://github.com/n8n-io/n8n/commit/667c15d0dfbdab0c29114d5002eed75031c79b42))
* **core:** Fix credentials test ([#6569](https://github.com/n8n-io/n8n/issues/6569)) ([1abd172](https://github.com/n8n-io/n8n/commit/1abd172f73e171e37c4cc3ccfaa395c6a46bdf48))
* **core:** Fix migrations for MySQL/MariaDB ([#6591](https://github.com/n8n-io/n8n/issues/6591)) ([29882a6](https://github.com/n8n-io/n8n/commit/29882a6f39dddcd1c8c107c20a548ce8dc665cba))
* **core:** Handle all uncaught exception, not just the ones from Axios ([#6666](https://github.com/n8n-io/n8n/issues/6666)) ([ff07595](https://github.com/n8n-io/n8n/commit/ff0759530df3780e8eb53a29ec4ab4e98e5755c6))
* **core:** Improve the performance of last 2 sqlite migrations ([#6522](https://github.com/n8n-io/n8n/issues/6522)) ([31cba87](https://github.com/n8n-io/n8n/commit/31cba87d307183d613890c7e6d627636b5280b52))
* **core:** Load SAML libraries dynamically ([#6690](https://github.com/n8n-io/n8n/issues/6690)) ([fce5609](https://github.com/n8n-io/n8n/commit/fce5609fa32b81ff8e44567233c77a7a1d6232df))
* **core:** Redirect user to previous url after SSO signin ([#6710](https://github.com/n8n-io/n8n/issues/6710)) ([08331c6](https://github.com/n8n-io/n8n/commit/08331c63fbc0d69d2203f14165b15e1a596788b0))
* **core:** Reduce memory consumption on `BinaryDataManager.init` ([#6633](https://github.com/n8n-io/n8n/issues/6633)) ([329d22f](https://github.com/n8n-io/n8n/commit/329d22f5d1f484d899df885a871f0f32839f0098))
* **core:** Remove typeorm patches, but still enforce transactions on every migration ([#6594](https://github.com/n8n-io/n8n/issues/6594)) ([9def7a7](https://github.com/n8n-io/n8n/commit/9def7a729b52cd6b4698c47e190e9e2bd7894da5)), closes [#6519](https://github.com/n8n-io/n8n/issues/6519)
* **core:** Rename to credential_stubs and variable_stubs.json ([#6528](https://github.com/n8n-io/n8n/issues/6528)) ([b06462f](https://github.com/n8n-io/n8n/commit/b06462f4415bd1143a00b4a66e6e626da8c52196))
* **core:** Support redis cluster in queue mode ([#6708](https://github.com/n8n-io/n8n/issues/6708)) ([4029386](https://github.com/n8n-io/n8n/commit/40293863492d73865f805870937e46f3d0bdaa56))
* **core:** Update docker compose setup for V1 images ([#6642](https://github.com/n8n-io/n8n/issues/6642)) ([05007d8](https://github.com/n8n-io/n8n/commit/05007d894e1bfa3550cfd865f85c2844b3db6eea))
* **core:** Upgrade semver to address CVE-2022-25883 ([#6689](https://github.com/n8n-io/n8n/issues/6689)) ([9daf944](https://github.com/n8n-io/n8n/commit/9daf944ba53937ddd41bd640a6d473d235f0e16f))
* **core:** Use `exec` in docker images to forward signals correctly ([#6732](https://github.com/n8n-io/n8n/issues/6732)) ([ed9f86b](https://github.com/n8n-io/n8n/commit/ed9f86bb95f7080335a336c866cd477669b02002))
* **core:** Use JWT as reset password token ([#6714](https://github.com/n8n-io/n8n/issues/6714)) ([89f4402](https://github.com/n8n-io/n8n/commit/89f44021b919181ad58c555a31071c286b866975))
* **core:** Use lower cased email for SAML email attribute ([#6663](https://github.com/n8n-io/n8n/issues/6663)) ([eedde24](https://github.com/n8n-io/n8n/commit/eedde24cc046ea517c6d6e455bcdd46a97e4c05b))
* **core:** Use owners file to export wf owners ([#6547](https://github.com/n8n-io/n8n/issues/6547)) ([4b755fb](https://github.com/n8n-io/n8n/commit/4b755fb0b441a37eb804c9e70d4b071a341f7155))
* **crowd.dev Node:** Fix documentation urls for crowd.dev credentials and nodes ([#6696](https://github.com/n8n-io/n8n/issues/6696)) ([acda7f2](https://github.com/n8n-io/n8n/commit/acda7f269f7b227d430e2308767e1676fda8e165))
* **editor:** Add default author name and email to source control settings ([#6543](https://github.com/n8n-io/n8n/issues/6543)) ([e1a02c7](https://github.com/n8n-io/n8n/commit/e1a02c76257de30e08878279dea33d7854d46938))
* **editor:** Add paywall state to non owner users for Variables ([#6679](https://github.com/n8n-io/n8n/issues/6679)) ([e7091d6](https://github.com/n8n-io/n8n/commit/e7091d6726eb98a194bc2614c0da332d348180dc))
* **editor:** Change default branchColor and remove label ([#6541](https://github.com/n8n-io/n8n/issues/6541)) ([186271e](https://github.com/n8n-io/n8n/commit/186271e939bca19ec9c94d9455e9430d8b8cf9d7))
* **editor:** Ensure default credential values are not detected as dirty state ([#6677](https://github.com/n8n-io/n8n/issues/6677)) ([c7b74c3](https://github.com/n8n-io/n8n/commit/c7b74c3c1fdd2f11b8650adf79052681c2f1e248))
* **editor:** Extend menu item and use it as a recursive component ([#6618](https://github.com/n8n-io/n8n/issues/6618)) ([d617f63](https://github.com/n8n-io/n8n/commit/d617f63ae9155c03dbf5e597db8e102c1f7a025f))
* **editor:** Hide Execute Node button for unknown nodes ([#6684](https://github.com/n8n-io/n8n/issues/6684)) ([6887b4e](https://github.com/n8n-io/n8n/commit/6887b4edeae6536f5b670c55637fde1c5dbd6e40))
* **editor:** Increase contrast ratio in execution list workflow names ([#6661](https://github.com/n8n-io/n8n/issues/6661)) ([c0b1cb2](https://github.com/n8n-io/n8n/commit/c0b1cb273e56c04abff5d9893a5e37cda6eb3383))
* **editor:** Make Source control branch select required ([#6619](https://github.com/n8n-io/n8n/issues/6619)) ([20737b5](https://github.com/n8n-io/n8n/commit/20737b532423c964bd70e0aa2aac2c9533b5c3d4))
* **editor:** Prevent keyboard shortcuts to edit workflows in readonly mode ([#6613](https://github.com/n8n-io/n8n/issues/6613)) ([7383e7f](https://github.com/n8n-io/n8n/commit/7383e7fd48b5c86d43fab4fa47cb1e7a4a4b4043))
* **editor:** Prevent RMC from loading schema if it's already cached ([#6695](https://github.com/n8n-io/n8n/issues/6695)) ([a79aa19](https://github.com/n8n-io/n8n/commit/a79aa198330808b7e45b217748fffdabb68098e2))
* **editor:** Remove global link styling in v1 banner ([#6705](https://github.com/n8n-io/n8n/issues/6705)) ([76a765a](https://github.com/n8n-io/n8n/commit/76a765a1517f53cb0c4f16a57bdd6f55bc3be0bd))
* **editor:** Show appropriate empty workflow list content when instance environment is readonly ([#6610](https://github.com/n8n-io/n8n/issues/6610)) ([7515f7d](https://github.com/n8n-io/n8n/commit/7515f7d52ae72fa1361687c43a9c29f585b3c6ce))
* **editor:** Show retry information in execution list only when it exists ([#6587](https://github.com/n8n-io/n8n/issues/6587)) ([3ca66be](https://github.com/n8n-io/n8n/commit/3ca66be38082e7a3866d53d07328be58e913067f))
* **editor:** Skip error line highlighting if out of range ([#6721](https://github.com/n8n-io/n8n/issues/6721)) ([a62d00a](https://github.com/n8n-io/n8n/commit/a62d00a4795d02a5905c5ddbae569f122a46a023))
* **editor:** Update design system menu item component ([#6659](https://github.com/n8n-io/n8n/issues/6659)) ([84466e9](https://github.com/n8n-io/n8n/commit/84466e983336a3cfa8c20b30ead8d58abbf07cf0))
* **FileMaker Node:** Improve returned error responses ([#6585](https://github.com/n8n-io/n8n/issues/6585)) ([91a052e](https://github.com/n8n-io/n8n/commit/91a052e4c53b6717d3a4e4d1034339012ce39c41))
* **FTP Node:** List recursive ignore . and .. to prevent infinite loops ([#6707](https://github.com/n8n-io/n8n/issues/6707)) ([995d5cc](https://github.com/n8n-io/n8n/commit/995d5cc47095e584c2a064dd5aa3841b3054ffd4))
* **GitLab Trigger Node:** Fix trigger activation 404 error ([#6711](https://github.com/n8n-io/n8n/issues/6711)) ([8ceb832](https://github.com/n8n-io/n8n/commit/8ceb8322ebfc1384291e8a0d5d07ee5c22d52142))
* **Gmail Trigger Node:** Early returns in case of no data ([#6727](https://github.com/n8n-io/n8n/issues/6727)) ([c2511a8](https://github.com/n8n-io/n8n/commit/c2511a829cfa40d4d9d570ad7724845c93544c3b))
* **Google BigQuery Node:** Error description improvement ([#6715](https://github.com/n8n-io/n8n/issues/6715)) ([95837d2](https://github.com/n8n-io/n8n/commit/95837d260466e8a4bd19c44390ce4557fa5c51cb))
* **Google Drive Node:** Fix regex in file RLC ([#6607](https://github.com/n8n-io/n8n/issues/6607)) ([5672146](https://github.com/n8n-io/n8n/commit/56721468dff51bb60ececc0472e2b9ca0740fcb1))
* **Google Drive Node:** URL parsing ([#6527](https://github.com/n8n-io/n8n/issues/6527)) ([d9ed0b3](https://github.com/n8n-io/n8n/commit/d9ed0b31b538320a67ee4e5c0cae34656c9f4334))
* **Google Sheets Node:** Incorrect read of 0 and false ([#6525](https://github.com/n8n-io/n8n/issues/6525)) ([806d134](https://github.com/n8n-io/n8n/commit/806d13460240abe94843e569b1820cd8d0d8edd1))
* **HTTP Request Node:** Cleanup circular references in response ([#6590](https://github.com/n8n-io/n8n/issues/6590)) ([aecc05b](https://github.com/n8n-io/n8n/commit/aecc05b787d09ba778adc5b4bf96abacc5a64204))
* **Merge Node:** Enrich input 2 fix ([#6526](https://github.com/n8n-io/n8n/issues/6526)) ([c82c7f1](https://github.com/n8n-io/n8n/commit/c82c7f19128df3a11d6d0f18e8d8dab57e6a3b8f))
* **Microsoft Outlook Node:** Fix issue with category not correctly applying ([#6583](https://github.com/n8n-io/n8n/issues/6583)) ([fc8ed55](https://github.com/n8n-io/n8n/commit/fc8ed55c0de7db4cf17f4f1bf417f6cbf48444c2))
* **Notion Node:** Version fix ([#6531](https://github.com/n8n-io/n8n/issues/6531)) ([38dc784](https://github.com/n8n-io/n8n/commit/38dc784d2eed25aae777c5c3c3fda1a35e20bd24))
* **Postgres Node:** Arrays in query replacement fix ([#6718](https://github.com/n8n-io/n8n/issues/6718)) ([4cae091](https://github.com/n8n-io/n8n/commit/4cae091cfb54701dfa51b5204799df0a8b4929cd))
* **Postgres Node:** For select queries, empty result should be be replaced with `{"success":true}` ([#6703](https://github.com/n8n-io/n8n/issues/6703)) ([250175d](https://github.com/n8n-io/n8n/commit/250175d066d6759f4a787371b47ed91ee62aab71))
* **Postgres Node:** Upsert does not fetch columns when schema other then public ([#6643](https://github.com/n8n-io/n8n/issues/6643)) ([aaa9ee3](https://github.com/n8n-io/n8n/commit/aaa9ee3949529a745e3b624716da1549ed571604))
* **Salesforce Node:** Fix typo for adding a contact to a campaign ([#6598](https://github.com/n8n-io/n8n/issues/6598)) ([7ffe3cb](https://github.com/n8n-io/n8n/commit/7ffe3cb36adeecaca6cc6ddf067a701ee55c18d1))
* **Sendy Node:** Fix issue with brand id not being sent ([#6530](https://github.com/n8n-io/n8n/issues/6530)) ([2e8dfb8](https://github.com/n8n-io/n8n/commit/2e8dfb86d4636781b319d6190e8be12e7661ee16))
* Stop n8n from complaining about credentials when saving a new workflow form a template ([#6671](https://github.com/n8n-io/n8n/issues/6671)) ([486d16b](https://github.com/n8n-io/n8n/commit/486d16bcdb6be12dd85f4af5f7de878d9d178fd6))
* **Strapi Node:** Fix issue with pagination ([#4991](https://github.com/n8n-io/n8n/issues/4991)) ([54444fa](https://github.com/n8n-io/n8n/commit/54444fa388da12d75553e66e53a8cf6f8a99b6fc))
* **Telegram Trigger Node:** Add guard to 'include' call on null or undefined ([#6730](https://github.com/n8n-io/n8n/issues/6730)) ([533b0ba](https://github.com/n8n-io/n8n/commit/533b0bac13d275753fee329bb4abe0c7aae5b48b))
* **XML Node:** Fix issue with not returning valid data ([#6565](https://github.com/n8n-io/n8n/issues/6565)) ([cdd215f](https://github.com/n8n-io/n8n/commit/cdd215f642b47413c05f229e641074d0d4048f68))
### Features
* Add crowd.dev node and trigger node ([#6082](https://github.com/n8n-io/n8n/issues/6082)) ([238a78f](https://github.com/n8n-io/n8n/commit/238a78f0582dbf439a9799de0edcb2e9bef29978))
* Add missing input panels to some trigger nodes ([#6518](https://github.com/n8n-io/n8n/issues/6518)) ([fdf8a42](https://github.com/n8n-io/n8n/commit/fdf8a428ed38bb3ceb2bc0e50b002b34843d8fc4))
* Add various source control improvements ([#6533](https://github.com/n8n-io/n8n/issues/6533)) ([68fdc20](https://github.com/n8n-io/n8n/commit/68fdc2078928be478a286774f2889feba1c3f5fe))
* **Airtable Node:** Overhaul ([#6200](https://github.com/n8n-io/n8n/issues/6200)) ([b69d20c](https://github.com/n8n-io/n8n/commit/b69d20c12ec1ad0395e23747ce5f1d437de0231b))
* Allow `eslint-config` to be externally consumable ([#6694](https://github.com/n8n-io/n8n/issues/6694)) ([3566c13](https://github.com/n8n-io/n8n/commit/3566c13afc9795206b5a4af7b06159e35b046e12))
* Allow hiding credential params on cloud ([#6687](https://github.com/n8n-io/n8n/issues/6687)) ([2af1c24](https://github.com/n8n-io/n8n/commit/2af1c24ead4c02e0588d4c2dfcf4a289f54388d4))
* **API:** Implement users account quota guards ([#6434](https://github.com/n8n-io/n8n/issues/6434)) ([e5620ab](https://github.com/n8n-io/n8n/commit/e5620ab1e49548e4c2ffd296e055f1caee94d2ba)), closes [#6636](https://github.com/n8n-io/n8n/issues/6636)
* **core:** Add cache service ([#6729](https://github.com/n8n-io/n8n/issues/6729)) ([c0d2bac](https://github.com/n8n-io/n8n/commit/c0d2bac94d732d4166633adf9c3b8eaf5d8046be))
* **core:** Only show V1 banner to users who migrated ([#6622](https://github.com/n8n-io/n8n/issues/6622)) ([071e56f](https://github.com/n8n-io/n8n/commit/071e56f7fde2fc4ffc7e3da92a069d8ed593bc60))
* **editor:** Implement new banners framework ([#6603](https://github.com/n8n-io/n8n/issues/6603)) ([4240e76](https://github.com/n8n-io/n8n/commit/4240e76253e02da13942d4b84a83ec22fd30aca3))
* **editor:** Load fixed template list as experiment ([#6632](https://github.com/n8n-io/n8n/issues/6632)) ([e996622](https://github.com/n8n-io/n8n/commit/e9966224ea555ce8f3a48872887a73ef879e47c3))
* **editor:** Prevent saving of workflow when canvas is loading ([#6497](https://github.com/n8n-io/n8n/issues/6497)) ([f89ef83](https://github.com/n8n-io/n8n/commit/f89ef83c766fafb1d0497ed91a74b93e8d2af1ec))
* **editor:** Removing `ph-no-capture` class from some elements ([#6674](https://github.com/n8n-io/n8n/issues/6674)) ([c3455a4](https://github.com/n8n-io/n8n/commit/c3455a4ad82d965c41267fea173feaad4800c43f))
* Environments release using source control ([#6653](https://github.com/n8n-io/n8n/issues/6653)) ([fc7aa8b](https://github.com/n8n-io/n8n/commit/fc7aa8bd664553c463536b6abe58a488e5e11147))
* **Google Cloud Storage Node:** Use streaming for file uploads ([#6462](https://github.com/n8n-io/n8n/issues/6462)) ([cd0e41a](https://github.com/n8n-io/n8n/commit/cd0e41a6b49a58bee95721363dd7e6c43de28725))
* **Google Drive Node:** Overhaul ([#5941](https://github.com/n8n-io/n8n/issues/5941)) ([d70a1cb](https://github.com/n8n-io/n8n/commit/d70a1cb0c82ee0a4b92776684c6c9079020d028f))
* **HTML Node:** 'Convert to table operation ([#6540](https://github.com/n8n-io/n8n/issues/6540)) ([8abb03d](https://github.com/n8n-io/n8n/commit/8abb03d7cf02ad7f03a0adffa646870df5f1a02c))
* **HTTP Request Node:** New http request generic custom auth credential ([#5798](https://github.com/n8n-io/n8n/issues/5798)) ([b17b458](https://github.com/n8n-io/n8n/commit/b17b4582a059104665888a2369c3e2256db4c1ed))
* **Matrix Node:** Allow setting filename if the binary data has none ([#6536](https://github.com/n8n-io/n8n/issues/6536)) ([8b76e98](https://github.com/n8n-io/n8n/commit/8b76e980852062b192a95593035697c43d6f808e))
* **Microsoft To Do Node:** Add an option to set a reminder when creating a task ([#5757](https://github.com/n8n-io/n8n/issues/5757)) ([b19833d](https://github.com/n8n-io/n8n/commit/b19833d673bd554ba86c0b234e8d13633912563a))
* **Notion Node:** Add option to update icon when updating a page ([#5670](https://github.com/n8n-io/n8n/issues/5670)) ([225e849](https://github.com/n8n-io/n8n/commit/225e849960ce65d7f85b482f05fb3d7ffb4f9427))
* **OpenAI Node:** Update max token limit to support newer model limits ([#6644](https://github.com/n8n-io/n8n/issues/6644)) ([26046f6](https://github.com/n8n-io/n8n/commit/26046f6fe8df9e6fe799f6253d086142f6ce7e53))
* **Read PDF Node:** Replace pdf-parse with pdfjs, and add support for streaming and encrypted PDFs ([#6640](https://github.com/n8n-io/n8n/issues/6640)) ([0a31b8e](https://github.com/n8n-io/n8n/commit/0a31b8e2b4aab8d74d80f76598900109fe19a0e8))
* **Rundeck Node:** Add support for node filters ([#5633](https://github.com/n8n-io/n8n/issues/5633)) ([1f70f49](https://github.com/n8n-io/n8n/commit/1f70f49ce5784baba7fd779b23209bae4f6b039a))
* **Slack Node:** Add option to include link to workflow in Slack node ([#6611](https://github.com/n8n-io/n8n/issues/6611)) ([aa53c46](https://github.com/n8n-io/n8n/commit/aa53c46367480e31642e807ad1abf149fd13eb28))
* **Strava Node:** Add hide_from_home field in Activity Update ([#5883](https://github.com/n8n-io/n8n/issues/5883)) ([7495e31](https://github.com/n8n-io/n8n/commit/7495e31a5b25e97683c7ea38225ba253d8fae8b7))
* **Telegram Node:** Add support for sending messages to forum topics ([#5746](https://github.com/n8n-io/n8n/issues/5746)) ([e6a81f0](https://github.com/n8n-io/n8n/commit/e6a81f0008fddfcfd5f1102c8e6e58650020d930))
* **Twitter Node:** Node overhaul ([#4788](https://github.com/n8n-io/n8n/issues/4788)) ([42721db](https://github.com/n8n-io/n8n/commit/42721dba80077fb796086a2bf0ecce256bf3a50f))
### Reverts
* Revert "test(editor): Add canvas actions E2E tests" (#6736) ([ed09e9c](https://github.com/n8n-io/n8n/commit/ed09e9c695109a715a4c8d47338bbb0b794eb009)), closes [#6736](https://github.com/n8n-io/n8n/issues/6736) [#6723](https://github.com/n8n-io/n8n/issues/6723)
## [1.0.1](https://github.com/n8n-io/n8n/compare/n8n@1.0.0...n8n@1.0.1) (2023-07-05)

View file

@ -1,6 +1,6 @@
{
"name": "n8n",
"version": "1.0.1",
"version": "1.1.0",
"private": true,
"homepage": "https://n8n.io",
"engines": {

View file

@ -1,6 +1,6 @@
{
"name": "@n8n/client-oauth2",
"version": "0.4.0",
"version": "0.5.0",
"scripts": {
"clean": "rimraf dist .turbo",
"dev": "pnpm watch",

View file

@ -4,7 +4,9 @@
/* eslint-disable @typescript-eslint/restrict-plus-operands */
/* eslint-disable @typescript-eslint/no-explicit-any */
import * as qs from 'querystring';
import { Agent } from 'https';
import axios from 'axios';
import type { AxiosRequestConfig } from 'axios';
import { getAuthError } from './utils';
import type { ClientOAuth2TokenData } from './ClientOAuth2Token';
import { ClientOAuth2Token } from './ClientOAuth2Token';
@ -18,6 +20,7 @@ export interface ClientOAuth2RequestObject {
body?: Record<string, any>;
query?: qs.ParsedUrlQuery;
headers?: Headers;
ignoreSSLIssues?: boolean;
}
export interface ClientOAuth2Options {
@ -32,6 +35,7 @@ export interface ClientOAuth2Options {
state?: string;
body?: Record<string, any>;
query?: qs.ParsedUrlQuery;
ignoreSSLIssues?: boolean;
}
class ResponseError extends Error {
@ -40,6 +44,8 @@ class ResponseError extends Error {
}
}
const sslIgnoringAgent = new Agent({ rejectUnauthorized: false });
/**
* Construct an object that can handle the multiple OAuth 2.0 flows.
*/
@ -86,7 +92,7 @@ export class ClientOAuth2 {
url += (url.indexOf('?') === -1 ? '?' : '&') + query;
}
const response = await axios.request({
const requestConfig: AxiosRequestConfig = {
url,
method: options.method,
data: qs.stringify(options.body),
@ -95,7 +101,13 @@ export class ClientOAuth2 {
// Axios rejects the promise by default for all status codes 4xx.
// We override this to reject promises only on 5xxs
validateStatus: (status) => status < 500,
});
};
if (options.ignoreSSLIssues) {
requestConfig.httpsAgent = sslIgnoringAgent;
}
const response = await axios.request(requestConfig);
const body = this.parseResponseBody<T>(response.data);

View file

@ -53,13 +53,13 @@ export class CodeFlow {
* the user access token.
*/
async getToken(
uri: string | URL,
urlString: string,
opts?: Partial<ClientOAuth2Options>,
): Promise<ClientOAuth2Token> {
const options = { ...this.client.options, ...opts };
const options: ClientOAuth2Options = { ...this.client.options, ...opts };
expects(options, 'clientId', 'accessTokenUri');
const url = uri instanceof URL ? uri : new URL(uri, DEFAULT_URL_BASE);
const url = new URL(urlString, DEFAULT_URL_BASE);
if (
typeof options.redirectUri === 'string' &&
typeof url.pathname === 'string' &&
@ -70,7 +70,7 @@ export class CodeFlow {
if (!url.search?.substring(1)) {
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
throw new TypeError(`Unable to process uri: ${uri.toString()}`);
throw new TypeError(`Unable to process uri: ${urlString}`);
}
const data =

View file

@ -63,14 +63,15 @@ export function auth(username: string, password: string): string {
*/
export function getRequestOptions(
{ url, method, body, query, headers }: ClientOAuth2RequestObject,
options: any,
options: ClientOAuth2Options,
): ClientOAuth2RequestObject {
const rOptions = {
url,
method,
body: { ...body, ...options.body },
query: { ...query, ...options.query },
headers: { ...headers, ...options.headers },
headers: headers ?? {},
ignoreSSLIssues: options.ignoreSSLIssues,
};
// if request authorization was overridden delete it from header
if (rOptions.headers.Authorization === '') {

View file

@ -1,6 +1,6 @@
{
"name": "n8n",
"version": "1.0.1",
"version": "1.1.0",
"description": "n8n Workflow Automation Tool",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -41,7 +41,6 @@ import {
TagRepository,
UserRepository,
VariablesRepository,
WebhookRepository,
WorkflowRepository,
WorkflowStatisticsRepository,
WorkflowTagMappingRepository,
@ -187,7 +186,6 @@ export async function init(testConnectionOptions?: ConnectionOptions): Promise<v
collections.Tag = Container.get(TagRepository);
collections.User = Container.get(UserRepository);
collections.Variables = Container.get(VariablesRepository);
collections.Webhook = Container.get(WebhookRepository);
collections.Workflow = Container.get(WorkflowRepository);
collections.WorkflowStatistics = Container.get(WorkflowStatisticsRepository);
collections.WorkflowTagMapping = Container.get(WorkflowTagMappingRepository);

View file

@ -56,7 +56,6 @@ import type {
TagRepository,
UserRepository,
VariablesRepository,
WebhookRepository,
WorkflowRepository,
WorkflowStatisticsRepository,
WorkflowTagMappingRepository,
@ -103,7 +102,6 @@ export interface IDatabaseCollections extends Record<string, Repository<any>> {
Tag: TagRepository;
User: UserRepository;
Variables: VariablesRepository;
Webhook: WebhookRepository;
Workflow: WorkflowRepository;
WorkflowStatistics: WorkflowStatisticsRepository;
WorkflowTagMapping: WorkflowTagMappingRepository;

View file

@ -11,7 +11,6 @@ const defaultUserProps = {
lastName: null,
email: null,
password: null,
resetPasswordToken: null,
};
export class Reset extends BaseCommand {

View file

@ -265,6 +265,7 @@ oauth2CredentialController.get(
redirectUri: `${getInstanceBaseUrl()}/${restEndpoint}/oauth2-credential/callback`,
scopes: split(scopes, ','),
scopesSeparator: scopes.includes(',') ? ',' : ' ',
ignoreSSLIssues: get(oauthCredentials, 'ignoreSSLIssues') as boolean,
};
if (oauthCredentials.grantType === 'pkce') {

View file

@ -1,6 +1,13 @@
import { BeforeUpdate, CreateDateColumn, UpdateDateColumn } from 'typeorm';
import {
BeforeInsert,
BeforeUpdate,
CreateDateColumn,
PrimaryColumn,
UpdateDateColumn,
} from 'typeorm';
import { IsDate, IsOptional } from 'class-validator';
import config from '@/config';
import { generateNanoId } from '../utils/generators';
const dbType = config.getEnv('database.type');
@ -14,18 +21,37 @@ const timestampSyntax = {
export const jsonColumnType = dbType === 'sqlite' ? 'simple-json' : 'json';
export const datetimeColumnType = dbType === 'postgresdb' ? 'timestamptz' : 'datetime';
export abstract class AbstractEntity {
@CreateDateColumn({
const tsColumnOptions = {
precision: 3,
default: () => timestampSyntax,
})
};
type Constructor<T> = new (...args: any[]) => T;
function mixinStringId<T extends Constructor<{}>>(base: T) {
class Derived extends base {
@PrimaryColumn('varchar')
id: string;
@BeforeInsert()
generateId() {
if (!this.id) {
this.id = generateNanoId();
}
}
}
return Derived;
}
function mixinTimestamps<T extends Constructor<{}>>(base: T) {
class Derived extends base {
@CreateDateColumn(tsColumnOptions)
@IsOptional() // ignored by validation because set at DB level
@IsDate()
createdAt: Date;
@UpdateDateColumn({
precision: 3,
default: () => timestampSyntax,
...tsColumnOptions,
onUpdate: timestampSyntax,
})
@IsOptional() // ignored by validation because set at DB level
@ -36,4 +62,12 @@ export abstract class AbstractEntity {
setUpdateDate(): void {
this.updatedAt = new Date();
}
}
return Derived;
}
class BaseEntity {}
/* eslint-disable @typescript-eslint/naming-convention */
export const WithStringId = mixinStringId(BaseEntity);
export const WithTimestamps = mixinTimestamps(BaseEntity);
export const WithTimestampsAndStringId = mixinStringId(WithTimestamps);

View file

@ -1,12 +1,12 @@
import { Column, Entity, ManyToOne, PrimaryColumn, Unique } from 'typeorm';
import { AbstractEntity } from './AbstractEntity';
import { WithTimestamps } from './AbstractEntity';
import { User } from './User';
export type AuthProviderType = 'ldap' | 'email' | 'saml'; // | 'google';
@Entity()
@Unique(['providerId', 'providerType'])
export class AuthIdentity extends AbstractEntity {
export class AuthIdentity extends WithTimestamps {
@Column()
userId: string;

View file

@ -1,30 +1,12 @@
import type { ICredentialNodeAccess } from 'n8n-workflow';
import { BeforeInsert, Column, Entity, Index, OneToMany, PrimaryColumn } from 'typeorm';
import { Column, Entity, Index, OneToMany } from 'typeorm';
import { IsArray, IsObject, IsString, Length } from 'class-validator';
import type { SharedCredentials } from './SharedCredentials';
import { AbstractEntity, jsonColumnType } from './AbstractEntity';
import { WithTimestampsAndStringId, jsonColumnType } from './AbstractEntity';
import type { ICredentialsDb } from '@/Interfaces';
import { generateNanoId } from '../utils/generators';
@Entity()
export class CredentialsEntity extends AbstractEntity implements ICredentialsDb {
constructor(data?: Partial<CredentialsEntity>) {
super();
Object.assign(this, data);
if (!this.id) {
this.id = generateNanoId();
}
}
@BeforeInsert()
nanoId(): void {
if (!this.id) {
this.id = generateNanoId();
}
}
@PrimaryColumn('varchar')
id: string;
export class CredentialsEntity extends WithTimestampsAndStringId implements ICredentialsDb {
@Column({ length: 128 })
@IsString({ message: 'Credential `name` must be of type string.' })
@Length(3, 128, {

View file

@ -1,9 +1,9 @@
import { MessageEventBusDestinationOptions } from 'n8n-workflow';
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { AbstractEntity, jsonColumnType } from './AbstractEntity';
import { WithTimestamps, jsonColumnType } from './AbstractEntity';
@Entity({ name: 'event_destinations' })
export class EventDestinations extends AbstractEntity {
export class EventDestinations extends WithTimestamps {
@PrimaryColumn('uuid')
id: string;

View file

@ -1,9 +1,9 @@
import { Column, Entity, JoinColumn, OneToMany, PrimaryColumn } from 'typeorm';
import type { InstalledNodes } from './InstalledNodes';
import { AbstractEntity } from './AbstractEntity';
import { WithTimestamps } from './AbstractEntity';
@Entity()
export class InstalledPackages extends AbstractEntity {
export class InstalledPackages extends WithTimestamps {
@PrimaryColumn()
packageName: string;

View file

@ -4,7 +4,7 @@ import { IsString, Length } from 'class-validator';
import type { User } from './User';
import type { SharedWorkflow } from './SharedWorkflow';
import type { SharedCredentials } from './SharedCredentials';
import { AbstractEntity } from './AbstractEntity';
import { WithTimestamps } from './AbstractEntity';
import { idStringifier } from '../utils/transformers';
export type RoleNames = 'owner' | 'member' | 'user' | 'editor';
@ -12,7 +12,7 @@ export type RoleScopes = 'global' | 'workflow' | 'credential';
@Entity()
@Unique(['scope', 'name'])
export class Role extends AbstractEntity {
export class Role extends WithTimestamps {
@PrimaryColumn({ transformer: idStringifier })
id: string;

View file

@ -2,10 +2,10 @@ import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
import { CredentialsEntity } from './CredentialsEntity';
import { User } from './User';
import { Role } from './Role';
import { AbstractEntity } from './AbstractEntity';
import { WithTimestamps } from './AbstractEntity';
@Entity()
export class SharedCredentials extends AbstractEntity {
export class SharedCredentials extends WithTimestamps {
@ManyToOne('Role', 'sharedCredentials', { nullable: false })
role: Role;

View file

@ -2,10 +2,10 @@ import { Column, Entity, ManyToOne, PrimaryColumn } from 'typeorm';
import { WorkflowEntity } from './WorkflowEntity';
import { User } from './User';
import { Role } from './Role';
import { AbstractEntity } from './AbstractEntity';
import { WithTimestamps } from './AbstractEntity';
@Entity()
export class SharedWorkflow extends AbstractEntity {
export class SharedWorkflow extends WithTimestamps {
@ManyToOne('Role', 'sharedWorkflows', { nullable: false })
role: Role;

View file

@ -1,30 +1,11 @@
import { BeforeInsert, Column, Entity, Index, ManyToMany, OneToMany, PrimaryColumn } from 'typeorm';
import { Column, Entity, Index, ManyToMany, OneToMany } from 'typeorm';
import { IsString, Length } from 'class-validator';
import type { WorkflowEntity } from './WorkflowEntity';
import type { WorkflowTagMapping } from './WorkflowTagMapping';
import { AbstractEntity } from './AbstractEntity';
import { generateNanoId } from '../utils/generators';
import { WithTimestampsAndStringId } from './AbstractEntity';
@Entity()
export class TagEntity extends AbstractEntity {
constructor(data?: Partial<TagEntity>) {
super();
Object.assign(this, data);
if (!this.id) {
this.id = generateNanoId();
}
}
@BeforeInsert()
nanoId() {
if (!this.id) {
this.id = generateNanoId();
}
}
@PrimaryColumn('varchar')
id: string;
export class TagEntity extends WithTimestampsAndStringId {
@Column({ length: 24 })
@Index({ unique: true })
@IsString({ message: 'Tag name must be of type string.' })

View file

@ -17,7 +17,7 @@ import type { SharedWorkflow } from './SharedWorkflow';
import type { SharedCredentials } from './SharedCredentials';
import { NoXss } from '../utils/customValidators';
import { objectRetriever, lowerCaser } from '../utils/transformers';
import { AbstractEntity, jsonColumnType } from './AbstractEntity';
import { WithTimestamps, jsonColumnType } from './AbstractEntity';
import type { IPersonalizationSurveyAnswers } from '@/Interfaces';
import type { AuthIdentity } from './AuthIdentity';
@ -26,7 +26,7 @@ export const MIN_PASSWORD_LENGTH = 8;
export const MAX_PASSWORD_LENGTH = 64;
@Entity()
export class User extends AbstractEntity implements IUser {
export class User extends WithTimestamps implements IUser {
@PrimaryGeneratedColumn('uuid')
id: string;

View file

@ -1,25 +1,8 @@
import { BeforeInsert, Column, Entity, PrimaryColumn } from 'typeorm';
import { generateNanoId } from '../utils/generators';
import { Column, Entity } from 'typeorm';
import { WithStringId } from './AbstractEntity';
@Entity()
export class Variables {
constructor(data?: Partial<Variables>) {
Object.assign(this, data);
if (!this.id) {
this.id = generateNanoId();
}
}
@BeforeInsert()
nanoId() {
if (!this.id) {
this.id = generateNanoId();
}
}
@PrimaryColumn('varchar')
id: string;
export class Variables extends WithStringId {
@Column('text')
key: string;

View file

@ -3,17 +3,7 @@ import { Length } from 'class-validator';
import { IConnections, IDataObject, IWorkflowSettings } from 'n8n-workflow';
import type { IBinaryKeyData, INode, IPairedItemData } from 'n8n-workflow';
import {
BeforeInsert,
Column,
Entity,
Index,
JoinColumn,
JoinTable,
ManyToMany,
OneToMany,
PrimaryColumn,
} from 'typeorm';
import { Column, Entity, Index, JoinColumn, JoinTable, ManyToMany, OneToMany } from 'typeorm';
import config from '@/config';
import type { TagEntity } from './TagEntity';
@ -21,30 +11,11 @@ import type { SharedWorkflow } from './SharedWorkflow';
import type { WorkflowStatistics } from './WorkflowStatistics';
import type { WorkflowTagMapping } from './WorkflowTagMapping';
import { objectRetriever, sqlite } from '../utils/transformers';
import { AbstractEntity, jsonColumnType } from './AbstractEntity';
import { WithTimestampsAndStringId, jsonColumnType } from './AbstractEntity';
import type { IWorkflowDb } from '@/Interfaces';
import { generateNanoId } from '../utils/generators';
@Entity()
export class WorkflowEntity extends AbstractEntity implements IWorkflowDb {
constructor(data?: Partial<WorkflowEntity>) {
super();
Object.assign(this, data);
if (!this.id) {
this.id = generateNanoId();
}
}
@BeforeInsert()
nanoId() {
if (!this.id) {
this.id = generateNanoId();
}
}
@PrimaryColumn('varchar')
id: string;
export class WorkflowEntity extends WithTimestampsAndStringId implements IWorkflowDb {
// TODO: Add XSS check
@Index({ unique: true })
@Length(1, 128, {

View file

@ -14,7 +14,7 @@ import { readFile as fsReadFile } from 'fs/promises';
import { Credentials, UserSettings } from 'n8n-core';
import type { IWorkflowToImport } from '@/Interfaces';
import type { ExportableCredential } from './types/exportableCredential';
import { Variables } from '@db/entities/Variables';
import type { Variables } from '@db/entities/Variables';
import { UM_FIX_INSTRUCTION } from '@/commands/BaseCommand';
import { SharedCredentials } from '@db/entities/SharedCredentials';
import type { WorkflowTagMapping } from '@db/entities/WorkflowTagMapping';
@ -576,7 +576,7 @@ export class SourceControlImportService {
if (overriddenKeys.length > 0 && valueOverrides) {
for (const key of overriddenKeys) {
result.imported.push(key);
const newVariable = new Variables({ key, value: valueOverrides[key] });
const newVariable = Db.collections.Variables.create({ key, value: valueOverrides[key] });
await Db.collections.Variables.save(newVariable);
}
}

View file

@ -4,7 +4,6 @@ import { audit } from '@/audit';
import { FILESYSTEM_INTERACTION_NODE_TYPES, FILESYSTEM_REPORT } from '@/audit/constants';
import { getRiskSection, saveManualTriggerWorkflow } from './utils';
import * as testDb from '../shared/testDb';
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
beforeAll(async () => {
await testDb.init();
@ -27,7 +26,7 @@ test('should report filesystem interaction nodes', async () => {
);
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
const details = new WorkflowEntity({
const details = Db.collections.Workflow.create({
name: 'My Test Workflow',
active: false,
connections: {},

View file

@ -9,7 +9,6 @@ import { toReportTitle } from '@/audit/utils';
import { mockInstance } from '../shared/utils/';
import { LoadNodesAndCredentials } from '@/LoadNodesAndCredentials';
import { NodeTypes } from '@/NodeTypes';
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
const nodesAndCredentials = mockInstance(LoadNodesAndCredentials);
nodesAndCredentials.getCustomDirectories.mockReturnValue([]);
@ -33,7 +32,7 @@ test('should report risky official nodes', async () => {
}, {});
const promises = Object.entries(map).map(async ([nodeType, nodeId]) => {
const details = new WorkflowEntity({
const details = Db.collections.Workflow.create({
name: 'My Test Workflow',
active: false,
connections: {},

View file

@ -47,17 +47,8 @@ describe('POST /login', () => {
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
password,
personalizationAnswers,
globalRole,
resetPasswordToken,
apiKey,
} = response.body.data;
const { id, email, firstName, lastName, password, personalizationAnswers, globalRole, apiKey } =
response.body.data;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBe(owner.email);
@ -66,7 +57,6 @@ describe('POST /login', () => {
expect(password).toBeUndefined();
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeDefined();
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');
@ -137,17 +127,8 @@ describe('GET /login', () => {
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
password,
personalizationAnswers,
globalRole,
resetPasswordToken,
apiKey,
} = response.body.data;
const { id, email, firstName, lastName, password, personalizationAnswers, globalRole, apiKey } =
response.body.data;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBeDefined();
@ -156,7 +137,6 @@ describe('GET /login', () => {
expect(password).toBeUndefined();
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeDefined();
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');
@ -173,17 +153,8 @@ describe('GET /login', () => {
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
password,
personalizationAnswers,
globalRole,
resetPasswordToken,
apiKey,
} = response.body.data;
const { id, email, firstName, lastName, password, personalizationAnswers, globalRole, apiKey } =
response.body.data;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBeDefined();
@ -192,7 +163,6 @@ describe('GET /login', () => {
expect(password).toBeUndefined();
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeDefined();
expect(globalRole.name).toBe('member');
expect(globalRole.scope).toBe('global');
@ -209,17 +179,8 @@ describe('GET /login', () => {
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
password,
personalizationAnswers,
globalRole,
resetPasswordToken,
apiKey,
} = response.body.data;
const { id, email, firstName, lastName, password, personalizationAnswers, globalRole, apiKey } =
response.body.data;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBe(owner.email);
@ -228,7 +189,6 @@ describe('GET /login', () => {
expect(password).toBeUndefined();
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeDefined();
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');
@ -245,17 +205,8 @@ describe('GET /login', () => {
expect(response.statusCode).toBe(200);
const {
id,
email,
firstName,
lastName,
password,
personalizationAnswers,
globalRole,
resetPasswordToken,
apiKey,
} = response.body.data;
const { id, email, firstName, lastName, password, personalizationAnswers, globalRole, apiKey } =
response.body.data;
expect(validator.isUUID(id)).toBe(true);
expect(email).toBe(member.email);
@ -264,7 +215,6 @@ describe('GET /login', () => {
expect(password).toBeUndefined();
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeDefined();
expect(globalRole.name).toBe('member');
expect(globalRole.scope).toBe('global');

View file

@ -42,7 +42,5 @@ test.skip('user-management:reset should reset DB to default user state', async (
expect(user.firstName).toBeNull();
expect(user.lastName).toBeNull();
expect(user.password).toBeNull();
expect(user.resetPasswordToken).toBeNull();
expect(user.resetPasswordTokenExpiration).toBeNull();
expect(user.personalizationAnswers).toBeNull();
});

View file

@ -53,7 +53,6 @@ describe('Owner shell', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
apiKey,
} = response.body.data;
@ -64,7 +63,6 @@ describe('Owner shell', () => {
expect(lastName).toBe(validPayload.lastName);
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(isPending).toBe(false);
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');
@ -198,7 +196,6 @@ describe('Member', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
apiKey,
} = response.body.data;
@ -209,7 +206,6 @@ describe('Member', () => {
expect(lastName).toBe(validPayload.lastName);
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(isPending).toBe(false);
expect(globalRole.name).toBe('member');
expect(globalRole.scope).toBe('global');
@ -334,7 +330,6 @@ describe('Owner', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
apiKey,
} = response.body.data;
@ -345,7 +340,6 @@ describe('Owner', () => {
expect(lastName).toBe(validPayload.lastName);
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(isPending).toBe(false);
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');

View file

@ -55,7 +55,6 @@ describe('POST /owner/setup', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
apiKey,
} = response.body.data;
@ -67,7 +66,6 @@ describe('POST /owner/setup', () => {
expect(personalizationAnswers).toBeNull();
expect(password).toBeUndefined();
expect(isPending).toBe(false);
expect(resetPasswordToken).toBeUndefined();
expect(globalRole.name).toBe('owner');
expect(globalRole.scope).toBe('global');
expect(apiKey).toBeUndefined();

View file

@ -73,7 +73,6 @@ describe('With license unlimited quota:users', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
createdAt,
updatedAt,
@ -85,7 +84,6 @@ describe('With license unlimited quota:users', () => {
expect(lastName).toBeDefined();
expect(personalizationAnswers).toBeUndefined();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(isPending).toBe(false);
expect(globalRole).toBeUndefined();
expect(createdAt).toBeDefined();
@ -144,7 +142,6 @@ describe('With license unlimited quota:users', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
createdAt,
updatedAt,
@ -156,7 +153,6 @@ describe('With license unlimited quota:users', () => {
expect(lastName).toBeDefined();
expect(personalizationAnswers).toBeUndefined();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(globalRole).toBeUndefined();
expect(createdAt).toBeDefined();
expect(isPending).toBeDefined();
@ -192,7 +188,6 @@ describe('With license unlimited quota:users', () => {
personalizationAnswers,
globalRole,
password,
resetPasswordToken,
isPending,
createdAt,
updatedAt,
@ -204,7 +199,6 @@ describe('With license unlimited quota:users', () => {
expect(lastName).toBeDefined();
expect(personalizationAnswers).toBeUndefined();
expect(password).toBeUndefined();
expect(resetPasswordToken).toBeUndefined();
expect(isPending).toBe(false);
expect(globalRole).toBeUndefined();
expect(createdAt).toBeDefined();

View file

@ -19,7 +19,7 @@ import { InstalledPackages } from '@db/entities/InstalledPackages';
import type { Role } from '@db/entities/Role';
import type { TagEntity } from '@db/entities/TagEntity';
import type { User } from '@db/entities/User';
import { WorkflowEntity } from '@db/entities/WorkflowEntity';
import type { WorkflowEntity } from '@db/entities/WorkflowEntity';
import { RoleRepository } from '@db/repositories';
import type { ICredentialsDb } from '@/Interfaces';
@ -412,7 +412,7 @@ export async function createManyWorkflows(
export async function createWorkflow(attributes: Partial<WorkflowEntity> = {}, user?: User) {
const { active, name, nodes, connections } = attributes;
const workflowEntity = new WorkflowEntity({
const workflowEntity = Db.collections.Workflow.create({
active: active ?? false,
name: name ?? 'test workflow',
nodes: nodes ?? [

View file

@ -1,6 +1,6 @@
{
"name": "n8n-core",
"version": "1.0.1",
"version": "1.1.0",
"description": "Core functionality of n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -1092,6 +1092,7 @@ export async function requestOAuth2(
clientSecret: credentials.clientSecret as string,
accessTokenUri: credentials.accessTokenUrl as string,
scopes: (credentials.scope as string).split(' '),
ignoreSSLIssues: credentials.ignoreSSLIssues as boolean,
});
let oauthTokenData = credentials.oauthTokenData as ClientOAuth2TokenData;
@ -1131,6 +1132,9 @@ export async function requestOAuth2(
},
oAuth2Options?.tokenType || oauthTokenData.tokenType,
);
(requestOptions as OptionsWithUri).rejectUnauthorized = !credentials.ignoreSSLIssues;
// Signs the request by adding authorization headers or query parameters depending
// on the token-type used.
const newRequestOptions = token.sign(requestOptions as ClientOAuth2RequestObject);

View file

@ -1,6 +1,6 @@
{
"name": "n8n-design-system",
"version": "1.0.0",
"version": "1.1.0",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",
"author": {

View file

@ -1,6 +1,6 @@
{
"name": "n8n-editor-ui",
"version": "1.0.1",
"version": "1.1.0",
"description": "Workflow Editor UI for n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -33,11 +33,6 @@ const tooltipOpenDelay = ref(300);
const currentBranch = computed(() => {
return sourceControlStore.preferences.branchName;
});
const featureEnabled = computed(() => window.localStorage.getItem('source-control'));
// TODO: use this for release
// const featureEnabled = computed(
// () => sourceControlStore.preferences.connected && sourceControlStore.preferences.branchName,
// );
const isInstanceOwner = computed(() => usersStore.isInstanceOwner);
const setupButtonTooltipPlacement = computed(() => (props.isCollapsed ? 'right' : 'top'));
@ -127,11 +122,11 @@ const goToSourceControlSetup = async () => {
<template>
<div
v-if="featureEnabled && isInstanceOwner"
v-if="sourceControlStore.isEnterpriseSourceControlEnabled && isInstanceOwner"
:class="{
[$style.sync]: true,
[$style.collapsed]: isCollapsed,
[$style.isConnected]: featureEnabled,
[$style.isConnected]: sourceControlStore.isEnterpriseSourceControlEnabled,
}"
:style="{ borderLeftColor: sourceControlStore.preferences.branchColor }"
data-test-id="main-sidebar-source-control"

View file

@ -19,10 +19,7 @@ let usersStore: ReturnType<typeof useUsersStore>;
const renderComponent = createComponentRenderer(MainSidebarSourceControl);
describe('MainSidebarSourceControl', () => {
const getItemSpy = vi.spyOn(Storage.prototype, 'getItem');
beforeEach(() => {
getItemSpy.mockReturnValue('true');
pinia = createTestingPinia({
initialState: {
[STORES.SETTINGS]: {
@ -32,31 +29,22 @@ describe('MainSidebarSourceControl', () => {
});
usersStore = useUsersStore(pinia);
vi.spyOn(usersStore, 'isInstanceOwner', 'get').mockReturnValue(true);
sourceControlStore = useSourceControlStore();
vi.spyOn(sourceControlStore, 'isEnterpriseSourceControlEnabled', 'get').mockReturnValue(true);
uiStore = useUIStore();
});
it('should render nothing', async () => {
getItemSpy.mockReturnValue(null);
const { container } = renderComponent({
props: { isCollapsed: false },
global: {
plugins: [pinia],
},
});
it('should render nothing when not instance owner', async () => {
vi.spyOn(usersStore, 'isInstanceOwner', 'get').mockReturnValue(false);
const { container } = renderComponent({ pinia, props: { isCollapsed: false } });
expect(container).toBeEmptyDOMElement();
});
it('should render empty content', async () => {
const { getByTestId } = renderComponent({
props: { isCollapsed: false },
global: {
plugins: [pinia],
},
});
it('should render empty content when instance owner but not connected', async () => {
const { getByTestId } = renderComponent({ pinia, props: { isCollapsed: false } });
expect(getByTestId('main-sidebar-source-control')).toBeInTheDocument();
expect(getByTestId('main-sidebar-source-control')).toBeEmptyDOMElement();
});
@ -76,10 +64,8 @@ describe('MainSidebarSourceControl', () => {
it('should render the appropriate content', async () => {
const { getByTestId, queryByTestId } = renderComponent({
pinia,
props: { isCollapsed: false },
global: {
plugins: [pinia],
},
});
expect(getByTestId('main-sidebar-source-control-connected')).toBeInTheDocument();
expect(queryByTestId('main-sidebar-source-control-setup')).not.toBeInTheDocument();
@ -90,10 +76,8 @@ describe('MainSidebarSourceControl', () => {
response: { status: 400 },
});
const { getAllByRole, getByRole } = renderComponent({
pinia,
props: { isCollapsed: false },
global: {
plugins: [pinia],
},
});
await userEvent.click(getAllByRole('button')[0]);
@ -108,10 +92,8 @@ describe('MainSidebarSourceControl', () => {
const openModalSpy = vi.spyOn(uiStore, 'openModalWithData');
const { getAllByRole, getByRole } = renderComponent({
pinia,
props: { isCollapsed: false },
global: {
plugins: [pinia],
},
});
await userEvent.click(getAllByRole('button')[0]);

View file

@ -1,6 +1,6 @@
{
"name": "n8n-node-dev",
"version": "1.0.1",
"version": "1.1.0",
"description": "CLI to simplify n8n credentials/node development",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -104,5 +104,12 @@ export class OAuth2Api implements ICredentialType {
],
default: 'header',
},
{
displayName: 'Ignore SSL Issues',
name: 'ignoreSSLIssues',
type: 'boolean',
default: false,
doNotInherit: true,
},
];
}

View file

@ -51,11 +51,11 @@ export async function lemlistApiRequestAllItems(
this: IExecuteFunctions | ILoadOptionsFunctions | IHookFunctions,
method: string,
endpoint: string,
qs: IDataObject = {},
) {
const returnData: IDataObject[] = [];
let responseData;
const qs: IDataObject = {};
qs.limit = 100;
qs.offset = 0;

View file

@ -123,7 +123,7 @@ export class Lemlist implements INodeType {
// https://developer.lemlist.com/#activities
const returnAll = this.getNodeParameter('returnAll', 0);
const returnAll = this.getNodeParameter('returnAll', i);
const qs = {} as IDataObject;
const filters = this.getNodeParameter('filters', i);
@ -132,11 +132,11 @@ export class Lemlist implements INodeType {
Object.assign(qs, filters);
}
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/activities', qs);
} else {
qs.limit = this.getNodeParameter('limit', i);
responseData = await lemlistApiRequest.call(this, 'GET', '/activities', {}, qs);
if (!returnAll) {
const limit = this.getNodeParameter('limit', 0);
responseData = responseData.slice(0, limit);
}
}
} else if (resource === 'campaign') {
@ -151,13 +151,15 @@ export class Lemlist implements INodeType {
// https://developer.lemlist.com/#list-all-campaigns
responseData = await lemlistApiRequest.call(this, 'GET', '/campaigns');
const returnAll = this.getNodeParameter('returnAll', i);
if (!returnAll) {
const limit = this.getNodeParameter('limit', i);
responseData = responseData.slice(0, limit);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/campaigns', {});
} else {
const qs = {
limit: this.getNodeParameter('limit', i),
};
responseData = await lemlistApiRequest.call(this, 'GET', '/campaigns', {}, qs);
}
}
} else if (resource === 'lead') {
@ -277,7 +279,7 @@ export class Lemlist implements INodeType {
const returnAll = this.getNodeParameter('returnAll', i);
if (returnAll) {
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/unsubscribes');
responseData = await lemlistApiRequestAllItems.call(this, 'GET', '/unsubscribes', {});
} else {
const qs = {
limit: this.getNodeParameter('limit', i),

View file

@ -1,6 +1,6 @@
{
"name": "n8n-nodes-base",
"version": "1.0.1",
"version": "1.1.0",
"description": "Base nodes of n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -1,6 +1,6 @@
{
"name": "n8n-workflow",
"version": "1.0.1",
"version": "1.1.0",
"description": "Workflow base code of n8n",
"license": "SEE LICENSE IN LICENSE.md",
"homepage": "https://n8n.io",

View file

@ -1116,6 +1116,7 @@ export interface INodeProperties {
extractValue?: INodePropertyValueExtractor;
modes?: INodePropertyMode[];
requiresDataPath?: 'single' | 'multiple';
doNotInherit?: boolean;
}
export interface INodePropertyModeTypeOptions {

View file

@ -1601,6 +1601,8 @@ export function mergeNodeProperties(
): void {
let existingIndex: number;
for (const property of addProperties) {
if (property.doNotInherit) continue;
existingIndex = mainProperties.findIndex((element) => element.name === property.name);
if (existingIndex === -1) {