diff --git a/core/js/dist/login.js b/core/js/dist/login.js
index bcc1e14efd6d880d9875b2ca37fd0df9c8c777e9..e975e29a6fac41cd2cfeb43d3021bb6cd5b5ae2a 100644
Binary files a/core/js/dist/login.js and b/core/js/dist/login.js differ
diff --git a/core/js/dist/login.js.map b/core/js/dist/login.js.map
index 7cd0090395645d22f07b0545773a4984fff85b84..23e5cc3ae8708414735474c3f0c6ffe9658f68cb 100644
Binary files a/core/js/dist/login.js.map and b/core/js/dist/login.js.map differ
diff --git a/core/js/dist/main.js b/core/js/dist/main.js
index 5d85464b6aadb832bd09871a5d3d7b655f6d057e..81af0225d0113b4c2d958fd185a19ad567e0657b 100644
Binary files a/core/js/dist/main.js and b/core/js/dist/main.js differ
diff --git a/core/js/dist/main.js.map b/core/js/dist/main.js.map
index e279acb2685c112b4c221a8f0bae7ac75a644f80..182d0167fb542898cf47037eba214d9e53e9c399 100644
Binary files a/core/js/dist/main.js.map and b/core/js/dist/main.js.map differ
diff --git a/core/js/dist/maintenance.js b/core/js/dist/maintenance.js
index 2b9aea4835f9e13ab667d0da7e97505261e375ec..e32bd1d2230ce448a11820f4ee07627424de69c1 100644
Binary files a/core/js/dist/maintenance.js and b/core/js/dist/maintenance.js differ
diff --git a/core/js/dist/maintenance.js.map b/core/js/dist/maintenance.js.map
index 9ce3ca434f80c33316340c5d87ddb9a527c32c21..1b51d5b4fc4632cb8f4d5678a45da6e993a1e4d2 100644
Binary files a/core/js/dist/maintenance.js.map and b/core/js/dist/maintenance.js.map differ
diff --git a/core/js/tests/specs/coreSpec.js b/core/js/tests/specs/coreSpec.js
index 70c8a27c14e15f19845ab82caff7de749ea0b5e5..c7399ea5d3ef6aa6d23b9afd96a064c0551c3cd2 100644
--- a/core/js/tests/specs/coreSpec.js
+++ b/core/js/tests/specs/coreSpec.js
@@ -35,213 +35,6 @@ describe('Core base tests', function() {
 			expect(OC.appswebroots).toBeDefined();
 		});
 	});
-	describe('basename', function() {
-		it('Returns the nothing if no file name given', function() {
-			expect(OC.basename('')).toEqual('');
-		});
-		it('Returns the nothing if dir is root', function() {
-			expect(OC.basename('/')).toEqual('');
-		});
-		it('Returns the same name if no path given', function() {
-			expect(OC.basename('some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if root path given', function() {
-			expect(OC.basename('/some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if double root path given', function() {
-			expect(OC.basename('//some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if subdir given without root', function() {
-			expect(OC.basename('subdir/some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if subdir given with root', function() {
-			expect(OC.basename('/subdir/some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if subdir given with double root', function() {
-			expect(OC.basename('//subdir/some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns the base name if subdir has dot', function() {
-			expect(OC.basename('/subdir.dat/some name.txt')).toEqual('some name.txt');
-		});
-		it('Returns dot if file name is dot', function() {
-			expect(OC.basename('/subdir/.')).toEqual('.');
-		});
-		// TODO: fix the source to make it work like PHP's basename
-		it('Returns the dir itself if no file name given', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.basename('subdir/')).toEqual('subdir');
-			expect(OC.basename('subdir/')).toEqual('');
-		});
-		it('Returns the dir itself if no file name given with root', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.basename('/subdir/')).toEqual('subdir');
-			expect(OC.basename('/subdir/')).toEqual('');
-		});
-	});
-	describe('dirname', function() {
-		it('Returns the nothing if no file name given', function() {
-			expect(OC.dirname('')).toEqual('');
-		});
-		it('Returns the root if dir is root', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.dirname('/')).toEqual('/');
-			expect(OC.dirname('/')).toEqual('');
-		});
-		it('Returns the root if dir is double root', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.dirname('//')).toEqual('/');
-			expect(OC.dirname('//')).toEqual('/'); // oh no...
-		});
-		it('Returns dot if dir is dot', function() {
-			expect(OC.dirname('.')).toEqual('.');
-		});
-		it('Returns dot if no root given', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.dirname('some dir')).toEqual('.');
-			expect(OC.dirname('some dir')).toEqual('some dir'); // oh no...
-		});
-		it('Returns the dir name if file name and root path given', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.dirname('/some name.txt')).toEqual('/');
-			expect(OC.dirname('/some name.txt')).toEqual('');
-		});
-		it('Returns the dir name if double root path given', function() {
-			expect(OC.dirname('//some name.txt')).toEqual('/'); // how lucky...
-		});
-		it('Returns the dir name if subdir given without root', function() {
-			expect(OC.dirname('subdir/some name.txt')).toEqual('subdir');
-		});
-		it('Returns the dir name if subdir given with root', function() {
-			expect(OC.dirname('/subdir/some name.txt')).toEqual('/subdir');
-		});
-		it('Returns the dir name if subdir given with double root', function() {
-			// TODO: fix the source to make it work like PHP's dirname
-			// expect(OC.dirname('//subdir/some name.txt')).toEqual('/subdir');
-			expect(OC.dirname('//subdir/some name.txt')).toEqual('//subdir'); // oh...
-		});
-		it('Returns the dir name if subdir has dot', function() {
-			expect(OC.dirname('/subdir.dat/some name.txt')).toEqual('/subdir.dat');
-		});
-		it('Returns the dir name if file name is dot', function() {
-			expect(OC.dirname('/subdir/.')).toEqual('/subdir');
-		});
-		it('Returns the dir name if no file name given', function() {
-			expect(OC.dirname('subdir/')).toEqual('subdir');
-		});
-		it('Returns the dir name if no file name given with root', function() {
-			expect(OC.dirname('/subdir/')).toEqual('/subdir');
-		});
-	});
-	describe('joinPaths', function() {
-		it('returns empty string with no or empty arguments', function() {
-			expect(OC.joinPaths()).toEqual('');
-			expect(OC.joinPaths('')).toEqual('');
-			expect(OC.joinPaths('', '')).toEqual('');
-		});
-		it('returns joined path sections', function() {
-			expect(OC.joinPaths('abc')).toEqual('abc');
-			expect(OC.joinPaths('abc', 'def')).toEqual('abc/def');
-			expect(OC.joinPaths('abc', 'def', 'ghi')).toEqual('abc/def/ghi');
-		});
-		it('keeps leading slashes', function() {
-			expect(OC.joinPaths('/abc')).toEqual('/abc');
-			expect(OC.joinPaths('/abc', '')).toEqual('/abc');
-			expect(OC.joinPaths('', '/abc')).toEqual('/abc');
-			expect(OC.joinPaths('/abc', 'def')).toEqual('/abc/def');
-			expect(OC.joinPaths('/abc', 'def', 'ghi')).toEqual('/abc/def/ghi');
-		});
-		it('keeps trailing slashes', function() {
-			expect(OC.joinPaths('', 'abc/')).toEqual('abc/');
-			expect(OC.joinPaths('abc/')).toEqual('abc/');
-			expect(OC.joinPaths('abc/', '')).toEqual('abc/');
-			expect(OC.joinPaths('abc', 'def/')).toEqual('abc/def/');
-			expect(OC.joinPaths('abc', 'def', 'ghi/')).toEqual('abc/def/ghi/');
-		});
-		it('splits paths in specified strings and discards extra slashes', function() {
-			expect(OC.joinPaths('//abc//')).toEqual('/abc/');
-			expect(OC.joinPaths('//abc//def//')).toEqual('/abc/def/');
-			expect(OC.joinPaths('//abc//', '//def//')).toEqual('/abc/def/');
-			expect(OC.joinPaths('//abc//', '//def//', '//ghi//')).toEqual('/abc/def/ghi/');
-			expect(OC.joinPaths('//abc//def//', '//ghi//jkl/mno/', '//pqr//'))
-				.toEqual('/abc/def/ghi/jkl/mno/pqr/');
-			expect(OC.joinPaths('/abc', '/def')).toEqual('/abc/def');
-			expect(OC.joinPaths('/abc/', '/def')).toEqual('/abc/def');
-			expect(OC.joinPaths('/abc/', 'def')).toEqual('/abc/def');
-		});
-		it('discards empty sections', function() {
-			expect(OC.joinPaths('abc', '', 'def')).toEqual('abc/def');
-		});
-		it('returns root if only slashes', function() {
-			expect(OC.joinPaths('//')).toEqual('/');
-			expect(OC.joinPaths('/', '/')).toEqual('/');
-			expect(OC.joinPaths('/', '//', '/')).toEqual('/');
-		});
-	});
-	describe('isSamePath', function() {
-		it('recognizes empty paths are equal', function() {
-			expect(OC.isSamePath('', '')).toEqual(true);
-			expect(OC.isSamePath('/', '')).toEqual(true);
-			expect(OC.isSamePath('//', '')).toEqual(true);
-			expect(OC.isSamePath('/', '/')).toEqual(true);
-			expect(OC.isSamePath('/', '//')).toEqual(true);
-		});
-		it('recognizes path with single sections as equal regardless of extra slashes', function() {
-			expect(OC.isSamePath('abc', 'abc')).toEqual(true);
-			expect(OC.isSamePath('/abc', 'abc')).toEqual(true);
-			expect(OC.isSamePath('//abc', 'abc')).toEqual(true);
-			expect(OC.isSamePath('abc', '/abc')).toEqual(true);
-			expect(OC.isSamePath('abc/', 'abc')).toEqual(true);
-			expect(OC.isSamePath('abc/', 'abc/')).toEqual(true);
-			expect(OC.isSamePath('/abc/', 'abc/')).toEqual(true);
-			expect(OC.isSamePath('/abc/', '/abc/')).toEqual(true);
-			expect(OC.isSamePath('//abc/', '/abc/')).toEqual(true);
-			expect(OC.isSamePath('//abc//', '/abc/')).toEqual(true);
-
-			expect(OC.isSamePath('abc', 'def')).toEqual(false);
-			expect(OC.isSamePath('/abc', 'def')).toEqual(false);
-			expect(OC.isSamePath('//abc', 'def')).toEqual(false);
-			expect(OC.isSamePath('abc', '/def')).toEqual(false);
-			expect(OC.isSamePath('abc/', 'def')).toEqual(false);
-			expect(OC.isSamePath('abc/', 'def/')).toEqual(false);
-			expect(OC.isSamePath('/abc/', 'def/')).toEqual(false);
-			expect(OC.isSamePath('/abc/', '/def/')).toEqual(false);
-			expect(OC.isSamePath('//abc/', '/def/')).toEqual(false);
-			expect(OC.isSamePath('//abc//', '/def/')).toEqual(false);
-		});
-		it('recognizes path with multiple sections as equal regardless of extra slashes', function() {
-			expect(OC.isSamePath('abc/def', 'abc/def')).toEqual(true);
-			expect(OC.isSamePath('/abc/def', 'abc/def')).toEqual(true);
-			expect(OC.isSamePath('abc/def', '/abc/def')).toEqual(true);
-			expect(OC.isSamePath('abc/def/', '/abc/def/')).toEqual(true);
-			expect(OC.isSamePath('/abc/def/', '/abc/def/')).toEqual(true);
-			expect(OC.isSamePath('/abc/def/', 'abc/def/')).toEqual(true);
-			expect(OC.isSamePath('//abc/def/', 'abc/def/')).toEqual(true);
-			expect(OC.isSamePath('//abc/def//', 'abc/def/')).toEqual(true);
-
-			expect(OC.isSamePath('abc/def', 'abc/ghi')).toEqual(false);
-			expect(OC.isSamePath('/abc/def', 'abc/ghi')).toEqual(false);
-			expect(OC.isSamePath('abc/def', '/abc/ghi')).toEqual(false);
-			expect(OC.isSamePath('abc/def/', '/abc/ghi/')).toEqual(false);
-			expect(OC.isSamePath('/abc/def/', '/abc/ghi/')).toEqual(false);
-			expect(OC.isSamePath('/abc/def/', 'abc/ghi/')).toEqual(false);
-			expect(OC.isSamePath('//abc/def/', 'abc/ghi/')).toEqual(false);
-			expect(OC.isSamePath('//abc/def//', 'abc/ghi/')).toEqual(false);
-		});
-		it('recognizes path entries with dot', function() {
-			expect(OC.isSamePath('.', '')).toEqual(true);
-			expect(OC.isSamePath('.', '.')).toEqual(true);
-			expect(OC.isSamePath('.', '/')).toEqual(true);
-			expect(OC.isSamePath('/.', '/')).toEqual(true);
-			expect(OC.isSamePath('/./', '/')).toEqual(true);
-			expect(OC.isSamePath('/./', '/.')).toEqual(true);
-			expect(OC.isSamePath('/./', '/./')).toEqual(true);
-			expect(OC.isSamePath('/./', '/./')).toEqual(true);
-
-			expect(OC.isSamePath('a/./b', 'a/b')).toEqual(true);
-			expect(OC.isSamePath('a/b/.', 'a/b')).toEqual(true);
-			expect(OC.isSamePath('./a/b', 'a/b')).toEqual(true);
-		});
-	});
 	describe('filePath', function() {
 		beforeEach(function() {
 			OC.webroot = 'http://localhost';
diff --git a/core/src/OC/index.js b/core/src/OC/index.js
index 01964b3ca4a5fef45f3c0a4d3edb49927488ac63..2a43d95eade6d0006274d21dd703fc03c9cb3020 100644
--- a/core/src/OC/index.js
+++ b/core/src/OC/index.js
@@ -38,7 +38,7 @@ import {
 	encodePath,
 	isSamePath,
 	joinPaths
-} from './path'
+} from '@nextcloud/paths'
 import {
 	build as buildQueryString,
 	parse as parseQueryString
@@ -189,10 +189,25 @@ export default {
 	/*
 	 * Path helpers
 	 */
+	/**
+	 * @deprecated 18.0.0 use https://www.npmjs.com/package/@nextcloud/paths
+	 */
 	basename,
+	/**
+	 * @deprecated 18.0.0 use https://www.npmjs.com/package/@nextcloud/paths
+	 */
 	encodePath,
+	/**
+	 * @deprecated 18.0.0 use https://www.npmjs.com/package/@nextcloud/paths
+	 */
 	dirname,
+	/**
+	 * @deprecated 18.0.0 use https://www.npmjs.com/package/@nextcloud/paths
+	 */
 	isSamePath,
+	/**
+	 * @deprecated 18.0.0 use https://www.npmjs.com/package/@nextcloud/paths
+	 */
 	joinPaths,
 
 	/**
diff --git a/core/src/OC/path.js b/core/src/OC/path.js
deleted file mode 100644
index 145c90d1e5e9ddbba31546dd699994d2387ffc80..0000000000000000000000000000000000000000
--- a/core/src/OC/path.js
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * @copyright 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @author 2019 Christoph Wurst <christoph@winzerhof-wurst.at>
- *
- * @license GNU AGPL version 3 or any later version
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-/**
- * URI-Encodes a file path but keep the path slashes.
- *
- * @param {String} path path
- * @returns {String} encoded path
- */
-export const encodePath = path => {
-	if (!path) {
-		return path
-	}
-	const parts = path.split('/')
-	const result = []
-	for (let i = 0; i < parts.length; i++) {
-		result.push(encodeURIComponent(parts[i]))
-	}
-	return result.join('/')
-}
-
-/**
- * Returns the base name of the given path.
- * For example for "/abc/somefile.txt" it will return "somefile.txt"
- *
- * @param {String} path path
- * @returns {String} base name
- */
-export const basename = path => path.replace(/\\/g, '/').replace(/.*\//, '')
-
-/**
- * Returns the dir name of the given path.
- * For example for "/abc/somefile.txt" it will return "/abc"
- *
- * @param {String} path path
- * @returns {String} dir name
- */
-export const dirname = path => path.replace(/\\/g, '/').replace(/\/[^/]*$/, '')
-
-/**
- * Returns whether the given paths are the same, without
- * leading, trailing or doubled slashes and also removing
- * the dot sections.
- *
- * @param {String} path1 first path
- * @param {String} path2 second path
- * @returns {bool} true if the paths are the same
- *
- * @since 9.0
- */
-export const isSamePath = (path1, path2) => {
-	const pathSections1 = (path1 || '').split('/').filter(p => p !== '.')
-	const pathSections2 = (path2 || '').split('/').filter(p => p !== '.')
-	path1 = joinPaths.apply(undefined, pathSections1)
-	path2 = joinPaths.apply(undefined, pathSections2)
-
-	return path1 === path2
-}
-
-/**
- * Join path sections
- *
- * @param {...String} path sections
- *
- * @returns {String} joined path, any leading or trailing slash
- * will be kept
- *
- * @since 8.2
- */
-export const joinPaths = (...args) => {
-	if (args.length < 1) {
-		return ''
-	}
-
-	// discard empty arguments
-	const nonEmptyArgs = args.filter(arg => arg.length > 0)
-	if (nonEmptyArgs.length < 1) {
-		return ''
-	}
-
-	const lastArg = nonEmptyArgs[nonEmptyArgs.length - 1]
-	const leadingSlash = nonEmptyArgs[0].charAt(0) === '/'
-	const trailingSlash = lastArg.charAt(lastArg.length - 1) === '/'
-	const sections = nonEmptyArgs.reduce((acc, section) => acc.concat(section.split('/')), [])
-
-	let first = !leadingSlash
-	const path = sections.reduce((acc, section) => {
-		if (section === '') {
-			return acc
-		}
-
-		if (first) {
-			first = false
-			return acc + section
-		}
-
-		return acc + '/' + section
-	}, '')
-
-	if (trailingSlash) {
-		// add it back
-		return path + '/'
-	}
-	return path
-}
diff --git a/package-lock.json b/package-lock.json
index 83a8c8e1e691a68ff0b3882705d6504dd8dd509e..5ce783aeb9cf862072b41e7545eb9ad9cd5fb559 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -866,6 +866,21 @@
         }
       }
     },
+    "@nextcloud/paths": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/@nextcloud/paths/-/paths-0.2.0.tgz",
+      "integrity": "sha512-C3jdAeCmZ6RcAESn4dGtVo914bmMvCgJeHNSyDW9lGJF0OAlP4mSZtPvh9hUVOZGeWuwQkSTyHbzdGTP7aFnTQ==",
+      "requires": {
+        "core-js": "3.1.4"
+      },
+      "dependencies": {
+        "core-js": {
+          "version": "3.1.4",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.1.4.tgz",
+          "integrity": "sha512-YNZN8lt82XIMLnLirj9MhKDFZHalwzzrL9YLt6eb0T5D0EDl4IQ90IGkua8mHbnxNrkj1d8hbdizMc0Qmg1WnQ=="
+        }
+      }
+    },
     "@nextcloud/router": {
       "version": "0.1.0",
       "resolved": "https://registry.npmjs.org/@nextcloud/router/-/router-0.1.0.tgz",
@@ -2831,9 +2846,9 @@
       }
     },
     "electron-to-chromium": {
-      "version": "1.3.274",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.274.tgz",
-      "integrity": "sha512-9bWkiXxGylowqMXoF1ec7k6akmsL2nOa1kzZ4CKzBuwK9WVz0VauE1w/RVyYraE1LpJM7+8fNCsW9b7ZSoxWIg=="
+      "version": "1.3.275",
+      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.275.tgz",
+      "integrity": "sha512-/YWtW/VapMnuYA1lNOaa1F4GhR1LBf+CUTp60lzDPEEh0XOzyOAyULyYZVF9vziZ3qSbTqCwmKwsyRXp66STbw=="
     },
     "elliptic": {
       "version": "6.5.1",
diff --git a/package.json b/package.json
index 1c666a49147db58dcd711c5acdc0b70eaa024332..9320d1fddb53fbb79ae0fbf2b9c48594eb82f435 100644
--- a/package.json
+++ b/package.json
@@ -27,6 +27,7 @@
     "@chenfengyuan/vue-qrcode": "^1.0.1",
     "@nextcloud/axios": "^0.4.1",
     "@nextcloud/event-bus": "^0.2.0",
+    "@nextcloud/paths": "^0.2.0",
     "@nextcloud/router": "^0.1.0",
     "autosize": "^4.0.2",
     "backbone": "^1.4.0",