├── .assets ├── img │ ├── customisation_1.png │ ├── logo_gray.svg │ ├── logo_primary.svg │ ├── logo_white.svg │ └── orgmode.gif └── raw │ ├── Makefile │ ├── navigation_00001.png │ ├── navigation_00002.png │ ├── navigation_00003.png │ ├── navigation_00004.png │ ├── navigation_00005.png │ ├── navigation_00006.png │ ├── navigation_00007.png │ ├── navigation_00008.png │ ├── navigation_00009.png │ ├── navigation_00010.png │ ├── navigation_00011.png │ ├── navigation_00012.png │ ├── orgmode_00001.png │ ├── orgmode_00002.png │ ├── orgmode_00003.png │ ├── orgmode_00004.png │ ├── orgmode_00005.png │ ├── orgmode_00006.png │ ├── orgmode_00007.png │ ├── orgmode_00008.png │ ├── orgmode_00009.png │ ├── orgmode_00010.png │ ├── orgmode_00011.png │ ├── orgmode_00012.png │ ├── orgmode_00013.png │ ├── orgmode_00014.png │ ├── photo.xcf │ ├── photo_management_0001.png │ ├── photo_management_0002.png │ ├── photo_management_0003.png │ ├── photo_management_0004.png │ ├── photo_management_0005.png │ ├── photo_management_0006.png │ ├── photo_management_0007.png │ ├── photo_management_0008.png │ ├── photo_management_0009.png │ └── photo_management_0010.png ├── .babelrc ├── .editorconfig ├── .eslintrc.json ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug.md │ ├── feature.md │ └── support.md └── stale.yml ├── .gitignore ├── CONTRIBUTING.md ├── Jenkinsfile ├── LICENSE ├── Makefile ├── README.md ├── client ├── assets │ ├── css │ │ ├── mixin.scss │ │ ├── reset.scss │ │ ├── videojs-custom.css │ │ └── videojs-sublime-skin.scss │ ├── fonts │ │ ├── SourceCodePro-Regular-400-latin-ext.woff2 │ │ ├── SourceCodePro-Regular-400-latin.woff2 │ │ ├── SourceCodePro-Semibold-600-latin-ext.woff2 │ │ └── SourceCodePro-Semibold-600-latin.woff2 │ ├── icons │ │ ├── delete.svg │ │ ├── edit.svg │ │ ├── empty_folder.svg │ │ ├── empty_search.svg │ │ ├── file.svg │ │ ├── folder.svg │ │ ├── music.png │ │ ├── photo.png │ │ ├── placeholder.png │ │ ├── share.svg │ │ ├── tag.svg │ │ └── video.png │ ├── img │ │ ├── alarm.svg │ │ ├── arrow-down-double.svg │ │ ├── arrow-down.svg │ │ ├── arrow-up-double.svg │ │ ├── arrow_bottom.svg │ │ ├── arrow_left.svg │ │ ├── arrow_left_white.svg │ │ ├── arrow_right.svg │ │ ├── arrow_right_white.svg │ │ ├── arrow_top.svg │ │ ├── bucket.svg │ │ ├── calendar.svg │ │ ├── calendar_white.svg │ │ ├── camera.svg │ │ ├── check.svg │ │ ├── close.svg │ │ ├── close_dark.svg │ │ ├── copy.svg │ │ ├── deadline.svg │ │ ├── download.svg │ │ ├── download_white.svg │ │ ├── dropbox.png │ │ ├── error.svg │ │ ├── eye.svg │ │ ├── fullscreen.svg │ │ ├── google-drive.png │ │ ├── grid.svg │ │ ├── info.svg │ │ ├── list.svg │ │ ├── loader.svg │ │ ├── loader_white.svg │ │ ├── location.svg │ │ ├── more.svg │ │ ├── pause.svg │ │ ├── play.svg │ │ ├── power.svg │ │ ├── refresh.svg │ │ ├── save.svg │ │ ├── schedule.svg │ │ ├── search.svg │ │ ├── search_dark.svg │ │ ├── sort.svg │ │ ├── stop.svg │ │ ├── todo_white.svg │ │ ├── upload_white.svg │ │ ├── volume.svg │ │ ├── volume_low.svg │ │ └── volume_mute.svg │ └── logo │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── app_icon.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── mstile-150x150.png │ │ ├── og-image.png │ │ └── safari-pinned-tab.svg ├── components │ ├── alert.js │ ├── alert.scss │ ├── animation.js │ ├── breadcrumb.js │ ├── breadcrumb.scss │ ├── bundle.js │ ├── button.js │ ├── button.scss │ ├── card.js │ ├── card.scss │ ├── confirm.js │ ├── container.js │ ├── container.scss │ ├── decorator.js │ ├── dropdown.js │ ├── dropdown.scss │ ├── events.js │ ├── fab.js │ ├── fab.scss │ ├── formbuilder.js │ ├── formbuilder.scss │ ├── icon.js │ ├── icon.scss │ ├── index.js │ ├── input.js │ ├── input.scss │ ├── loader.js │ ├── loader.scss │ ├── mapshot.js │ ├── mapshot.scss │ ├── modal.js │ ├── modal.scss │ ├── ngif.js │ ├── notification.js │ ├── notification.scss │ ├── popup.js │ ├── popup.scss │ ├── prompt.js │ ├── textarea.js │ ├── textarea.scss │ ├── textarea.woff │ ├── upload_queue.js │ ├── upload_queue.scss │ ├── video.js │ └── video.scss ├── helpers │ ├── ajax.js │ ├── backpressure.js │ ├── bcrypt.js │ ├── cache.js │ ├── cache_state.js │ ├── common.js │ ├── crypto.js │ ├── events.js │ ├── form.js │ ├── format.js │ ├── index.js │ ├── memory.js │ ├── mimetype.js │ ├── navigate.js │ ├── notify.js │ ├── org.js │ ├── path.js │ ├── popup.js │ ├── random.js │ ├── settings.js │ └── upload.js ├── index.html ├── index.js ├── locales │ ├── _.json │ ├── az.json │ ├── be.json │ ├── bg.json │ ├── ca.json │ ├── cs.json │ ├── da.json │ ├── de.json │ ├── el.json │ ├── es.json │ ├── et.json │ ├── eu.json │ ├── fi.json │ ├── fr.json │ ├── gl.json │ ├── hr.json │ ├── hu.json │ ├── id.json │ ├── index.js │ ├── is.json │ ├── it.json │ ├── ja.json │ ├── ka.json │ ├── ko.json │ ├── lt.json │ ├── lv.json │ ├── mn.json │ ├── nb.json │ ├── nl.json │ ├── pl.json │ ├── pt.json │ ├── ro.json │ ├── ru.json │ ├── sk.json │ ├── sl.json │ ├── sr.json │ ├── sv.json │ ├── th.json │ ├── tr.json │ ├── uk.json │ ├── vi.json │ ├── zh.json │ └── zh_tw.json ├── model │ ├── admin.js │ ├── audit.js │ ├── chromecast.js │ ├── config.js │ ├── files.js │ ├── index.js │ ├── log.js │ ├── session.js │ ├── share.js │ └── tags.js ├── pages │ ├── adminpage.js │ ├── adminpage.scss │ ├── adminpage │ │ ├── about.js │ │ ├── about.scss │ │ ├── backend.js │ │ ├── backend.scss │ │ ├── home.js │ │ ├── index.js │ │ ├── logger.js │ │ ├── logger.scss │ │ ├── loginpage.js │ │ ├── settings.js │ │ ├── setup.js │ │ └── setup.scss │ ├── connectpage.js │ ├── connectpage.scss │ ├── connectpage │ │ ├── forkme.js │ │ ├── forkme.scss │ │ ├── form.js │ │ ├── form.scss │ │ └── index.js │ ├── error.scss │ ├── filespage.helper.js │ ├── filespage.js │ ├── filespage.scss │ ├── filespage │ │ ├── breadcrumb.js │ │ ├── filesystem.js │ │ ├── filesystem.scss │ │ ├── filezone.js │ │ ├── filezone.scss │ │ ├── frequently_access.js │ │ ├── frequently_access.scss │ │ ├── index.js │ │ ├── share.js │ │ ├── share.scss │ │ ├── sidebar.js │ │ ├── sidebar.scss │ │ ├── submenu.js │ │ ├── submenu.scss │ │ ├── tag.js │ │ ├── tag.scss │ │ ├── thing-existing.js │ │ ├── thing-new.js │ │ └── thing.scss │ ├── homepage.js │ ├── index.js │ ├── logout.js │ ├── notfoundpage.js │ ├── sharepage.js │ ├── sharepage.scss │ ├── tagspage.js │ ├── tagspage.scss │ ├── viewerpage.js │ ├── viewerpage.scss │ └── viewerpage │ │ ├── appframe.js │ │ ├── appframe.scss │ │ ├── audioplayer.js │ │ ├── audioplayer.scss │ │ ├── ebookviewer.js │ │ ├── ebookviewer.scss │ │ ├── editor.js │ │ ├── editor.scss │ │ ├── editor │ │ ├── clike.js │ │ ├── clojure.js │ │ ├── cmake.js │ │ ├── commonlisp.js │ │ ├── css.js │ │ ├── diff.js │ │ ├── dockerfile.js │ │ ├── elm.js │ │ ├── emacs-org.js │ │ ├── erlang.js │ │ ├── go.js │ │ ├── htmlmixed.js │ │ ├── javascript.js │ │ ├── jsx.js │ │ ├── keymap_base.js │ │ ├── keymap_vim.js │ │ ├── lua.js │ │ ├── orgmode.js │ │ ├── perl.js │ │ ├── php.js │ │ ├── properties.js │ │ ├── python.js │ │ ├── r.js │ │ ├── ruby.js │ │ ├── rust.js │ │ ├── sass.js │ │ ├── shell.js │ │ ├── sparql.js │ │ ├── spreadsheet.js │ │ ├── sql.js │ │ ├── stex.js │ │ ├── text.js │ │ ├── xml.js │ │ ├── yaml-frontmatter.js │ │ └── yaml.js │ │ ├── filedownloader.js │ │ ├── filedownloader.scss │ │ ├── formviewer.js │ │ ├── formviewer.scss │ │ ├── ide.js │ │ ├── ide.scss │ │ ├── image_exif.js │ │ ├── image_exif.scss │ │ ├── imageviewer.js │ │ ├── imageviewer.scss │ │ ├── index.js │ │ ├── menubar.js │ │ ├── menubar.scss │ │ ├── org_viewer.js │ │ ├── org_viewer.scss │ │ ├── pager.js │ │ ├── pager.scss │ │ ├── pdfviewer.js │ │ ├── pdfviewer.scss │ │ ├── pdfviewer_lazy.js │ │ ├── videoplayer.js │ │ └── videoplayer.scss ├── router.js └── worker │ └── sw_cache.js ├── cmd └── main.go ├── config ├── config.json ├── emacs.el └── mime.json ├── docker ├── Dockerfile └── docker-compose.yml ├── embed.go ├── go.mod ├── go.sum ├── package.json ├── public ├── Makefile ├── assets │ ├── boot │ │ ├── common.js │ │ ├── ctrl_boot.d.ts │ │ ├── ctrl_boot_backoffice.js │ │ ├── ctrl_boot_frontoffice.js │ │ ├── router_backoffice.js │ │ └── router_frontoffice.js │ ├── components │ │ ├── breadcrumb.css │ │ ├── breadcrumb.js │ │ ├── decorator_shell_filemanager.css │ │ ├── decorator_shell_filemanager.js │ │ ├── dropdown.css │ │ ├── dropdown.js │ │ ├── fab.css │ │ ├── fab.js │ │ ├── form.js │ │ ├── icon.js │ │ ├── loader.js │ │ ├── modal.css │ │ ├── modal.js │ │ ├── notification.css │ │ ├── notification.js │ │ ├── sidebar.css │ │ ├── sidebar.js │ │ └── skeleton.js │ ├── css │ │ ├── designsystem.css │ │ ├── designsystem_alert.css │ │ ├── designsystem_box.css │ │ ├── designsystem_button.css │ │ ├── designsystem_checkbox.css │ │ ├── designsystem_container.css │ │ ├── designsystem_darkmode.css │ │ ├── designsystem_dropdown.css │ │ ├── designsystem_formbuilder.css │ │ ├── designsystem_icon.css │ │ ├── designsystem_input.css │ │ ├── designsystem_inputgroup.css │ │ ├── designsystem_skeleton.css │ │ ├── designsystem_textarea.css │ │ └── designsystem_utils.css │ ├── embed │ │ ├── filestash-map.js │ │ └── filestash-table.js │ ├── fonts │ │ ├── SourceCodePro-Regular-400-latin-ext.woff2 │ │ ├── SourceCodePro-Regular-400-latin.woff2 │ │ ├── SourceCodePro-Semibold-600-latin-ext.woff2 │ │ └── SourceCodePro-Semibold-600-latin.woff2 │ ├── helpers │ │ ├── loader.d.ts │ │ ├── loader.js │ │ ├── loader_wasm.js │ │ ├── log.d.ts │ │ ├── log.js │ │ └── sdk.js │ ├── index.js │ ├── lib │ │ ├── ajax.js │ │ ├── animate.d.ts │ │ ├── animate.js │ │ ├── assert.js │ │ ├── chromecast.js │ │ ├── dom.d.ts │ │ ├── dom.js │ │ ├── error.d.ts │ │ ├── error.js │ │ ├── form.d.ts │ │ ├── form.js │ │ ├── path.js │ │ ├── polyfill.js │ │ ├── random.d.ts │ │ ├── random.js │ │ ├── rx.d.ts │ │ ├── rx.js │ │ ├── settings.js │ │ ├── skeleton │ │ │ ├── index.d.ts │ │ │ ├── index.js │ │ │ ├── lifecycle.d.ts │ │ │ ├── lifecycle.js │ │ │ ├── router.d.ts │ │ │ └── router.js │ │ ├── store.js │ │ └── vendor │ │ │ ├── bcrypt.js │ │ │ ├── codemirror │ │ │ ├── .editorconfig │ │ │ ├── .gitattributes │ │ │ ├── .npmignore │ │ │ ├── AUTHORS │ │ │ ├── CHANGELOG.md │ │ │ ├── CONTRIBUTING.md │ │ │ ├── LICENSE │ │ │ ├── README.md │ │ │ ├── addon │ │ │ │ ├── comment │ │ │ │ │ ├── comment.js │ │ │ │ │ └── continuecomment.js │ │ │ │ ├── dialog │ │ │ │ │ ├── dialog.css │ │ │ │ │ └── dialog.js │ │ │ │ ├── display │ │ │ │ │ ├── autorefresh.js │ │ │ │ │ ├── fullscreen.css │ │ │ │ │ ├── fullscreen.js │ │ │ │ │ ├── panel.js │ │ │ │ │ ├── placeholder.js │ │ │ │ │ └── rulers.js │ │ │ │ ├── edit │ │ │ │ │ ├── closebrackets.js │ │ │ │ │ ├── closetag.js │ │ │ │ │ ├── continuelist.js │ │ │ │ │ ├── matchbrackets.js │ │ │ │ │ ├── matchtags.js │ │ │ │ │ └── trailingspace.js │ │ │ │ ├── fold │ │ │ │ │ ├── brace-fold.js │ │ │ │ │ ├── comment-fold.js │ │ │ │ │ ├── foldcode.js │ │ │ │ │ ├── foldgutter.css │ │ │ │ │ ├── foldgutter.js │ │ │ │ │ ├── indent-fold.js │ │ │ │ │ ├── markdown-fold.js │ │ │ │ │ └── xml-fold.js │ │ │ │ ├── hint │ │ │ │ │ ├── anyword-hint.js │ │ │ │ │ ├── css-hint.js │ │ │ │ │ ├── html-hint.js │ │ │ │ │ ├── javascript-hint.js │ │ │ │ │ ├── show-hint.css │ │ │ │ │ ├── show-hint.js │ │ │ │ │ ├── sql-hint.js │ │ │ │ │ └── xml-hint.js │ │ │ │ ├── lint │ │ │ │ │ ├── coffeescript-lint.js │ │ │ │ │ ├── css-lint.js │ │ │ │ │ ├── html-lint.js │ │ │ │ │ ├── javascript-lint.js │ │ │ │ │ ├── json-lint.js │ │ │ │ │ ├── lint.css │ │ │ │ │ ├── lint.js │ │ │ │ │ └── yaml-lint.js │ │ │ │ ├── merge │ │ │ │ │ ├── merge.css │ │ │ │ │ └── merge.js │ │ │ │ ├── mode │ │ │ │ │ ├── loadmode.js │ │ │ │ │ ├── multiplex.js │ │ │ │ │ ├── multiplex_test.js │ │ │ │ │ ├── overlay.js │ │ │ │ │ └── simple.js │ │ │ │ ├── runmode │ │ │ │ │ ├── colorize.js │ │ │ │ │ ├── runmode-standalone.js │ │ │ │ │ ├── runmode.js │ │ │ │ │ └── runmode.node.js │ │ │ │ ├── scroll │ │ │ │ │ ├── annotatescrollbar.js │ │ │ │ │ ├── scrollpastend.js │ │ │ │ │ ├── simplescrollbars.css │ │ │ │ │ └── simplescrollbars.js │ │ │ │ ├── search │ │ │ │ │ ├── jump-to-line.js │ │ │ │ │ ├── match-highlighter.js │ │ │ │ │ ├── matchesonscrollbar.css │ │ │ │ │ ├── matchesonscrollbar.js │ │ │ │ │ ├── search.js │ │ │ │ │ └── searchcursor.js │ │ │ │ ├── selection │ │ │ │ │ ├── active-line.js │ │ │ │ │ ├── mark-selection.js │ │ │ │ │ └── selection-pointer.js │ │ │ │ ├── tern │ │ │ │ │ ├── tern.css │ │ │ │ │ ├── tern.js │ │ │ │ │ └── worker.js │ │ │ │ └── wrap │ │ │ │ │ └── hardwrap.js │ │ │ ├── bin │ │ │ │ ├── authors.sh │ │ │ │ ├── lint │ │ │ │ ├── release │ │ │ │ ├── source-highlight │ │ │ │ └── upload-release.js │ │ │ ├── demo │ │ │ │ ├── activeline.html │ │ │ │ ├── anywordhint.html │ │ │ │ ├── bidi.html │ │ │ │ ├── btree.html │ │ │ │ ├── buffers.html │ │ │ │ ├── changemode.html │ │ │ │ ├── closebrackets.html │ │ │ │ ├── closetag.html │ │ │ │ ├── complete.html │ │ │ │ ├── emacs.html │ │ │ │ ├── folding.html │ │ │ │ ├── fullscreen.html │ │ │ │ ├── hardwrap.html │ │ │ │ ├── html5complete.html │ │ │ │ ├── indentwrap.html │ │ │ │ ├── lint.html │ │ │ │ ├── loadmode.html │ │ │ │ ├── marker.html │ │ │ │ ├── markselection.html │ │ │ │ ├── matchhighlighter.html │ │ │ │ ├── matchtags.html │ │ │ │ ├── merge.html │ │ │ │ ├── multiplex.html │ │ │ │ ├── mustache.html │ │ │ │ ├── panel.html │ │ │ │ ├── placeholder.html │ │ │ │ ├── preview.html │ │ │ │ ├── requirejs.html │ │ │ │ ├── resize.html │ │ │ │ ├── rulers.html │ │ │ │ ├── runmode-standalone.html │ │ │ │ ├── runmode.html │ │ │ │ ├── search.html │ │ │ │ ├── simplemode.html │ │ │ │ ├── simplescrollbars.html │ │ │ │ ├── spanaffectswrapping_shim.html │ │ │ │ ├── sublime.html │ │ │ │ ├── tern.html │ │ │ │ ├── theme.html │ │ │ │ ├── trailingspace.html │ │ │ │ ├── variableheight.html │ │ │ │ ├── vim.html │ │ │ │ ├── visibletabs.html │ │ │ │ ├── widget.html │ │ │ │ └── xmlcomplete.html │ │ │ ├── doc │ │ │ │ ├── activebookmark.js │ │ │ │ ├── docs.css │ │ │ │ ├── internals.html │ │ │ │ ├── logo.png │ │ │ │ ├── logo.svg │ │ │ │ ├── manual.html │ │ │ │ ├── realworld.html │ │ │ │ ├── releases.html │ │ │ │ ├── reporting.html │ │ │ │ ├── source_sans.woff │ │ │ │ ├── upgrade_v2.2.html │ │ │ │ ├── upgrade_v3.html │ │ │ │ ├── upgrade_v4.html │ │ │ │ └── yinyang.png │ │ │ ├── index.html │ │ │ ├── keymap │ │ │ │ ├── emacs.js │ │ │ │ ├── sublime.js │ │ │ │ └── vim.js │ │ │ ├── lib │ │ │ │ ├── codemirror.css │ │ │ │ └── codemirror.js │ │ │ ├── mode │ │ │ │ ├── apl │ │ │ │ │ ├── apl.js │ │ │ │ │ └── index.html │ │ │ │ ├── asciiarmor │ │ │ │ │ ├── asciiarmor.js │ │ │ │ │ └── index.html │ │ │ │ ├── asn.1 │ │ │ │ │ ├── asn.1.js │ │ │ │ │ └── index.html │ │ │ │ ├── asterisk │ │ │ │ │ ├── asterisk.js │ │ │ │ │ └── index.html │ │ │ │ ├── brainfuck │ │ │ │ │ ├── brainfuck.js │ │ │ │ │ └── index.html │ │ │ │ ├── clike │ │ │ │ │ ├── clike.js │ │ │ │ │ ├── index.html │ │ │ │ │ ├── scala.html │ │ │ │ │ └── test.js │ │ │ │ ├── clojure │ │ │ │ │ ├── clojure.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── cmake │ │ │ │ │ ├── cmake.js │ │ │ │ │ └── index.html │ │ │ │ ├── cobol │ │ │ │ │ ├── cobol.js │ │ │ │ │ └── index.html │ │ │ │ ├── coffeescript │ │ │ │ │ ├── coffeescript.js │ │ │ │ │ └── index.html │ │ │ │ ├── commonlisp │ │ │ │ │ ├── commonlisp.js │ │ │ │ │ └── index.html │ │ │ │ ├── crystal │ │ │ │ │ ├── crystal.js │ │ │ │ │ └── index.html │ │ │ │ ├── css │ │ │ │ │ ├── css.js │ │ │ │ │ ├── gss.html │ │ │ │ │ ├── gss_test.js │ │ │ │ │ ├── index.html │ │ │ │ │ ├── less.html │ │ │ │ │ ├── less_test.js │ │ │ │ │ ├── scss.html │ │ │ │ │ ├── scss_test.js │ │ │ │ │ └── test.js │ │ │ │ ├── cypher │ │ │ │ │ ├── cypher.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── d │ │ │ │ │ ├── d.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── dart │ │ │ │ │ ├── dart.js │ │ │ │ │ └── index.html │ │ │ │ ├── diff │ │ │ │ │ ├── diff.js │ │ │ │ │ └── index.html │ │ │ │ ├── django │ │ │ │ │ ├── django.js │ │ │ │ │ └── index.html │ │ │ │ ├── dockerfile │ │ │ │ │ ├── dockerfile.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── dtd │ │ │ │ │ ├── dtd.js │ │ │ │ │ └── index.html │ │ │ │ ├── dylan │ │ │ │ │ ├── dylan.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── ebnf │ │ │ │ │ ├── ebnf.js │ │ │ │ │ └── index.html │ │ │ │ ├── ecl │ │ │ │ │ ├── ecl.js │ │ │ │ │ └── index.html │ │ │ │ ├── eiffel │ │ │ │ │ ├── eiffel.js │ │ │ │ │ └── index.html │ │ │ │ ├── elm │ │ │ │ │ ├── elm.js │ │ │ │ │ └── index.html │ │ │ │ ├── erlang │ │ │ │ │ ├── erlang.js │ │ │ │ │ └── index.html │ │ │ │ ├── factor │ │ │ │ │ ├── factor.js │ │ │ │ │ └── index.html │ │ │ │ ├── fcl │ │ │ │ │ ├── fcl.js │ │ │ │ │ └── index.html │ │ │ │ ├── forth │ │ │ │ │ ├── forth.js │ │ │ │ │ └── index.html │ │ │ │ ├── fortran │ │ │ │ │ ├── fortran.js │ │ │ │ │ └── index.html │ │ │ │ ├── gas │ │ │ │ │ ├── gas.js │ │ │ │ │ └── index.html │ │ │ │ ├── gfm │ │ │ │ │ ├── gfm.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── gherkin │ │ │ │ │ ├── gherkin.js │ │ │ │ │ └── index.html │ │ │ │ ├── go │ │ │ │ │ ├── go.js │ │ │ │ │ └── index.html │ │ │ │ ├── groovy │ │ │ │ │ ├── groovy.js │ │ │ │ │ └── index.html │ │ │ │ ├── haml │ │ │ │ │ ├── haml.js │ │ │ │ │ ├── index.html │ │ │ │ │ └── test.js │ │ │ │ ├── handlebars │ │ │ │ │ ├── handlebars.js │ │ │ │ │ └── index.html │ │ │ │ ├── haskell-literate │ │ │ │ │ ├── haskell-literate.js │ │ │ │ │ └── index.html │ │ │ │ ├── haskell │ │ │ │ │ ├── haskell.js │ │ │ │ │ └── index.html │ │ │ │ ├── haxe │ │ │ │ │ ├── haxe.js │ │ │ │ │ └── index.html │ │ │ │ ├── htmlembedded │ │ │ │ │ ├── htmlembedded.js │ │ │ │ │ └── index.html │ │ │ │ ├── htmlmixed │ │ │ │ │ ├── htmlmixed.js │ │ │ │ │ └── index.html │ │ │ │ ├── http │ │ │ │ │ ├── http.js │ │ │ │ │ └── index.html │ │ │ │ ├── idl │ │ │ │ │ ├── idl.js │ │ │ │ │ └── index.html │ │ │ │ ├── index.html │ │ │ │ ├── javascript │ │ │ │ │ ├── index.html │ │ │ │ │ ├── javascript.js │ │ │ │ │ ├── json-ld.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── typescript.html │ │ │ │ ├── jinja2 │ │ │ │ │ ├── index.html │ │ │ │ │ └── jinja2.js │ │ │ │ ├── jsx │ │ │ │ │ ├── index.html │ │ │ │ │ ├── jsx.js │ │ │ │ │ └── test.js │ │ │ │ ├── julia │ │ │ │ │ ├── index.html │ │ │ │ │ └── julia.js │ │ │ │ ├── livescript │ │ │ │ │ ├── index.html │ │ │ │ │ └── livescript.js │ │ │ │ ├── lua │ │ │ │ │ ├── index.html │ │ │ │ │ └── lua.js │ │ │ │ ├── markdown │ │ │ │ │ ├── index.html │ │ │ │ │ ├── markdown.js │ │ │ │ │ └── test.js │ │ │ │ ├── mathematica │ │ │ │ │ ├── index.html │ │ │ │ │ └── mathematica.js │ │ │ │ ├── mbox │ │ │ │ │ ├── index.html │ │ │ │ │ └── mbox.js │ │ │ │ ├── meta.js │ │ │ │ ├── mirc │ │ │ │ │ ├── index.html │ │ │ │ │ └── mirc.js │ │ │ │ ├── mllike │ │ │ │ │ ├── index.html │ │ │ │ │ └── mllike.js │ │ │ │ ├── modelica │ │ │ │ │ ├── index.html │ │ │ │ │ └── modelica.js │ │ │ │ ├── mscgen │ │ │ │ │ ├── index.html │ │ │ │ │ ├── mscgen.js │ │ │ │ │ ├── mscgen_test.js │ │ │ │ │ ├── msgenny_test.js │ │ │ │ │ └── xu_test.js │ │ │ │ ├── mumps │ │ │ │ │ ├── index.html │ │ │ │ │ └── mumps.js │ │ │ │ ├── nginx │ │ │ │ │ ├── index.html │ │ │ │ │ └── nginx.js │ │ │ │ ├── nsis │ │ │ │ │ ├── index.html │ │ │ │ │ └── nsis.js │ │ │ │ ├── ntriples │ │ │ │ │ ├── index.html │ │ │ │ │ └── ntriples.js │ │ │ │ ├── octave │ │ │ │ │ ├── index.html │ │ │ │ │ └── octave.js │ │ │ │ ├── oz │ │ │ │ │ ├── index.html │ │ │ │ │ └── oz.js │ │ │ │ ├── pascal │ │ │ │ │ ├── index.html │ │ │ │ │ └── pascal.js │ │ │ │ ├── pegjs │ │ │ │ │ ├── index.html │ │ │ │ │ └── pegjs.js │ │ │ │ ├── perl │ │ │ │ │ ├── index.html │ │ │ │ │ └── perl.js │ │ │ │ ├── php │ │ │ │ │ ├── index.html │ │ │ │ │ ├── php.js │ │ │ │ │ └── test.js │ │ │ │ ├── pig │ │ │ │ │ ├── index.html │ │ │ │ │ └── pig.js │ │ │ │ ├── powershell │ │ │ │ │ ├── index.html │ │ │ │ │ ├── powershell.js │ │ │ │ │ └── test.js │ │ │ │ ├── properties │ │ │ │ │ ├── index.html │ │ │ │ │ └── properties.js │ │ │ │ ├── protobuf │ │ │ │ │ ├── index.html │ │ │ │ │ └── protobuf.js │ │ │ │ ├── pug │ │ │ │ │ ├── index.html │ │ │ │ │ └── pug.js │ │ │ │ ├── puppet │ │ │ │ │ ├── index.html │ │ │ │ │ └── puppet.js │ │ │ │ ├── python │ │ │ │ │ ├── index.html │ │ │ │ │ ├── python.js │ │ │ │ │ └── test.js │ │ │ │ ├── q │ │ │ │ │ ├── index.html │ │ │ │ │ └── q.js │ │ │ │ ├── r │ │ │ │ │ ├── index.html │ │ │ │ │ └── r.js │ │ │ │ ├── rpm │ │ │ │ │ ├── changes │ │ │ │ │ │ └── index.html │ │ │ │ │ ├── index.html │ │ │ │ │ └── rpm.js │ │ │ │ ├── rst │ │ │ │ │ ├── index.html │ │ │ │ │ └── rst.js │ │ │ │ ├── ruby │ │ │ │ │ ├── index.html │ │ │ │ │ ├── ruby.js │ │ │ │ │ └── test.js │ │ │ │ ├── rust │ │ │ │ │ ├── index.html │ │ │ │ │ ├── rust.js │ │ │ │ │ └── test.js │ │ │ │ ├── sas │ │ │ │ │ ├── index.html │ │ │ │ │ └── sas.js │ │ │ │ ├── sass │ │ │ │ │ ├── index.html │ │ │ │ │ ├── sass.js │ │ │ │ │ └── test.js │ │ │ │ ├── scheme │ │ │ │ │ ├── index.html │ │ │ │ │ └── scheme.js │ │ │ │ ├── shell │ │ │ │ │ ├── index.html │ │ │ │ │ ├── shell.js │ │ │ │ │ └── test.js │ │ │ │ ├── sieve │ │ │ │ │ ├── index.html │ │ │ │ │ └── sieve.js │ │ │ │ ├── slim │ │ │ │ │ ├── index.html │ │ │ │ │ ├── slim.js │ │ │ │ │ └── test.js │ │ │ │ ├── smalltalk │ │ │ │ │ ├── index.html │ │ │ │ │ └── smalltalk.js │ │ │ │ ├── smarty │ │ │ │ │ ├── index.html │ │ │ │ │ └── smarty.js │ │ │ │ ├── solr │ │ │ │ │ ├── index.html │ │ │ │ │ └── solr.js │ │ │ │ ├── soy │ │ │ │ │ ├── index.html │ │ │ │ │ ├── soy.js │ │ │ │ │ └── test.js │ │ │ │ ├── sparql │ │ │ │ │ ├── index.html │ │ │ │ │ └── sparql.js │ │ │ │ ├── spreadsheet │ │ │ │ │ ├── index.html │ │ │ │ │ └── spreadsheet.js │ │ │ │ ├── sql │ │ │ │ │ ├── index.html │ │ │ │ │ └── sql.js │ │ │ │ ├── stex │ │ │ │ │ ├── index.html │ │ │ │ │ ├── stex.js │ │ │ │ │ └── test.js │ │ │ │ ├── stylus │ │ │ │ │ ├── index.html │ │ │ │ │ └── stylus.js │ │ │ │ ├── swift │ │ │ │ │ ├── index.html │ │ │ │ │ ├── swift.js │ │ │ │ │ └── test.js │ │ │ │ ├── tcl │ │ │ │ │ ├── index.html │ │ │ │ │ └── tcl.js │ │ │ │ ├── textile │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── textile.js │ │ │ │ ├── tiddlywiki │ │ │ │ │ ├── index.html │ │ │ │ │ ├── tiddlywiki.css │ │ │ │ │ └── tiddlywiki.js │ │ │ │ ├── tiki │ │ │ │ │ ├── index.html │ │ │ │ │ ├── tiki.css │ │ │ │ │ └── tiki.js │ │ │ │ ├── toml │ │ │ │ │ ├── index.html │ │ │ │ │ └── toml.js │ │ │ │ ├── tornado │ │ │ │ │ ├── index.html │ │ │ │ │ └── tornado.js │ │ │ │ ├── troff │ │ │ │ │ ├── index.html │ │ │ │ │ └── troff.js │ │ │ │ ├── ttcn-cfg │ │ │ │ │ ├── index.html │ │ │ │ │ └── ttcn-cfg.js │ │ │ │ ├── ttcn │ │ │ │ │ ├── index.html │ │ │ │ │ └── ttcn.js │ │ │ │ ├── turtle │ │ │ │ │ ├── index.html │ │ │ │ │ └── turtle.js │ │ │ │ ├── twig │ │ │ │ │ ├── index.html │ │ │ │ │ └── twig.js │ │ │ │ ├── vb │ │ │ │ │ ├── index.html │ │ │ │ │ └── vb.js │ │ │ │ ├── vbscript │ │ │ │ │ ├── index.html │ │ │ │ │ └── vbscript.js │ │ │ │ ├── velocity │ │ │ │ │ ├── index.html │ │ │ │ │ └── velocity.js │ │ │ │ ├── verilog │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── verilog.js │ │ │ │ ├── vhdl │ │ │ │ │ ├── index.html │ │ │ │ │ └── vhdl.js │ │ │ │ ├── vue │ │ │ │ │ ├── index.html │ │ │ │ │ └── vue.js │ │ │ │ ├── wast │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── wast.js │ │ │ │ ├── webidl │ │ │ │ │ ├── index.html │ │ │ │ │ └── webidl.js │ │ │ │ ├── xml │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── xml.js │ │ │ │ ├── xquery │ │ │ │ │ ├── index.html │ │ │ │ │ ├── test.js │ │ │ │ │ └── xquery.js │ │ │ │ ├── yacas │ │ │ │ │ ├── index.html │ │ │ │ │ └── yacas.js │ │ │ │ ├── yaml-frontmatter │ │ │ │ │ ├── index.html │ │ │ │ │ └── yaml-frontmatter.js │ │ │ │ ├── yaml │ │ │ │ │ ├── index.html │ │ │ │ │ └── yaml.js │ │ │ │ └── z80 │ │ │ │ │ ├── index.html │ │ │ │ │ └── z80.js │ │ │ ├── package.json │ │ │ ├── rollup.config.js │ │ │ ├── src │ │ │ │ ├── addon │ │ │ │ │ └── runmode │ │ │ │ │ │ ├── codemirror-standalone.js │ │ │ │ │ │ ├── codemirror.node.js │ │ │ │ │ │ ├── runmode-standalone.js │ │ │ │ │ │ └── runmode.node.js │ │ │ │ ├── codemirror.js │ │ │ │ ├── display │ │ │ │ │ ├── Display.js │ │ │ │ │ ├── focus.js │ │ │ │ │ ├── gutters.js │ │ │ │ │ ├── highlight_worker.js │ │ │ │ │ ├── line_numbers.js │ │ │ │ │ ├── mode_state.js │ │ │ │ │ ├── operations.js │ │ │ │ │ ├── scroll_events.js │ │ │ │ │ ├── scrollbars.js │ │ │ │ │ ├── scrolling.js │ │ │ │ │ ├── selection.js │ │ │ │ │ ├── update_display.js │ │ │ │ │ ├── update_line.js │ │ │ │ │ ├── update_lines.js │ │ │ │ │ └── view_tracking.js │ │ │ │ ├── edit │ │ │ │ │ ├── CodeMirror.js │ │ │ │ │ ├── commands.js │ │ │ │ │ ├── deleteNearSelection.js │ │ │ │ │ ├── drop_events.js │ │ │ │ │ ├── fromTextArea.js │ │ │ │ │ ├── global_events.js │ │ │ │ │ ├── key_events.js │ │ │ │ │ ├── legacy.js │ │ │ │ │ ├── main.js │ │ │ │ │ ├── methods.js │ │ │ │ │ ├── mouse_events.js │ │ │ │ │ ├── options.js │ │ │ │ │ └── utils.js │ │ │ │ ├── input │ │ │ │ │ ├── ContentEditableInput.js │ │ │ │ │ ├── TextareaInput.js │ │ │ │ │ ├── indent.js │ │ │ │ │ ├── input.js │ │ │ │ │ ├── keymap.js │ │ │ │ │ ├── keynames.js │ │ │ │ │ └── movement.js │ │ │ │ ├── line │ │ │ │ │ ├── highlight.js │ │ │ │ │ ├── line_data.js │ │ │ │ │ ├── pos.js │ │ │ │ │ ├── saw_special_spans.js │ │ │ │ │ ├── spans.js │ │ │ │ │ └── utils_line.js │ │ │ │ ├── measurement │ │ │ │ │ ├── position_measurement.js │ │ │ │ │ └── widgets.js │ │ │ │ ├── model │ │ │ │ │ ├── Doc.js │ │ │ │ │ ├── change_measurement.js │ │ │ │ │ ├── changes.js │ │ │ │ │ ├── chunk.js │ │ │ │ │ ├── document_data.js │ │ │ │ │ ├── history.js │ │ │ │ │ ├── line_widget.js │ │ │ │ │ ├── mark_text.js │ │ │ │ │ ├── selection.js │ │ │ │ │ └── selection_updates.js │ │ │ │ ├── modes.js │ │ │ │ └── util │ │ │ │ │ ├── StringStream.js │ │ │ │ │ ├── bidi.js │ │ │ │ │ ├── browser.js │ │ │ │ │ ├── dom.js │ │ │ │ │ ├── event.js │ │ │ │ │ ├── feature_detection.js │ │ │ │ │ ├── misc.js │ │ │ │ │ └── operation_group.js │ │ │ └── theme │ │ │ │ ├── 3024-day.css │ │ │ │ ├── 3024-night.css │ │ │ │ ├── abbott.css │ │ │ │ ├── abcdef.css │ │ │ │ ├── ambiance-mobile.css │ │ │ │ ├── ambiance.css │ │ │ │ ├── ayu-dark.css │ │ │ │ ├── ayu-mirage.css │ │ │ │ ├── base16-dark.css │ │ │ │ ├── base16-light.css │ │ │ │ ├── bespin.css │ │ │ │ ├── blackboard.css │ │ │ │ ├── cobalt.css │ │ │ │ ├── colorforth.css │ │ │ │ ├── darcula.css │ │ │ │ ├── dracula.css │ │ │ │ ├── duotone-dark.css │ │ │ │ ├── duotone-light.css │ │ │ │ ├── eclipse.css │ │ │ │ ├── elegant.css │ │ │ │ ├── erlang-dark.css │ │ │ │ ├── gruvbox-dark.css │ │ │ │ ├── hopscotch.css │ │ │ │ ├── icecoder.css │ │ │ │ ├── idea.css │ │ │ │ ├── isotope.css │ │ │ │ ├── juejin.css │ │ │ │ ├── lesser-dark.css │ │ │ │ ├── liquibyte.css │ │ │ │ ├── lucario.css │ │ │ │ ├── material-darker.css │ │ │ │ ├── material-ocean.css │ │ │ │ ├── material-palenight.css │ │ │ │ ├── material.css │ │ │ │ ├── mbo.css │ │ │ │ ├── mdn-like.css │ │ │ │ ├── midnight.css │ │ │ │ ├── monokai.css │ │ │ │ ├── moxer.css │ │ │ │ ├── neat.css │ │ │ │ ├── neo.css │ │ │ │ ├── night.css │ │ │ │ ├── nord.css │ │ │ │ ├── oceanic-next.css │ │ │ │ ├── panda-syntax.css │ │ │ │ ├── paraiso-dark.css │ │ │ │ ├── paraiso-light.css │ │ │ │ ├── pastel-on-dark.css │ │ │ │ ├── railscasts.css │ │ │ │ ├── rubyblue.css │ │ │ │ ├── seti.css │ │ │ │ ├── shadowfox.css │ │ │ │ ├── solarized.css │ │ │ │ ├── ssms.css │ │ │ │ ├── the-matrix.css │ │ │ │ ├── tomorrow-night-bright.css │ │ │ │ ├── tomorrow-night-eighties.css │ │ │ │ ├── ttcn.css │ │ │ │ ├── twilight.css │ │ │ │ ├── vibrant-ink.css │ │ │ │ ├── xq-dark.css │ │ │ │ ├── xq-light.css │ │ │ │ ├── yeti.css │ │ │ │ ├── yonce.css │ │ │ │ └── zenburn.css │ │ │ ├── epub │ │ │ ├── epub.min.js │ │ │ └── zip.min.js │ │ │ ├── exif-js.js │ │ │ ├── hlsjs │ │ │ ├── hls.js │ │ │ └── hls.js.map │ │ │ ├── leaflet │ │ │ ├── Control.Draw.js │ │ │ ├── Leaflet.Draw.Event.js │ │ │ ├── Leaflet.draw.js │ │ │ ├── Toolbar.js │ │ │ ├── Tooltip.js │ │ │ ├── assets │ │ │ │ └── rulers.png │ │ │ ├── draw │ │ │ │ ├── DrawToolbar.js │ │ │ │ └── handler │ │ │ │ │ ├── Draw.Circle.js │ │ │ │ │ ├── Draw.CircleMarker.js │ │ │ │ │ ├── Draw.Feature.js │ │ │ │ │ ├── Draw.Marker.js │ │ │ │ │ ├── Draw.Polygon.js │ │ │ │ │ ├── Draw.Polyline.js │ │ │ │ │ ├── Draw.Rectangle.js │ │ │ │ │ └── Draw.SimpleShape.js │ │ │ ├── edit │ │ │ │ ├── EditToolbar.js │ │ │ │ └── handler │ │ │ │ │ ├── Edit.Circle.js │ │ │ │ │ ├── Edit.CircleMarker.js │ │ │ │ │ ├── Edit.Marker.js │ │ │ │ │ ├── Edit.Poly.js │ │ │ │ │ ├── Edit.Rectangle.js │ │ │ │ │ ├── Edit.SimpleShape.js │ │ │ │ │ ├── EditToolbar.Delete.js │ │ │ │ │ └── EditToolbar.Edit.js │ │ │ ├── ext │ │ │ │ ├── GeometryUtil.js │ │ │ │ ├── LatLngUtil.js │ │ │ │ ├── LineUtil.Intersect.js │ │ │ │ ├── Polygon.Intersect.js │ │ │ │ ├── Polyline.Intersect.js │ │ │ │ └── TouchEvents.js │ │ │ ├── images │ │ │ │ ├── layers.png │ │ │ │ ├── marker-icon.png │ │ │ │ ├── marker-shadow.png │ │ │ │ └── spritesheet.svg │ │ │ ├── leaflet-measure.css │ │ │ ├── leaflet-measure.js │ │ │ ├── leaflet.css │ │ │ ├── leaflet.draw.css │ │ │ ├── leaflet.js │ │ │ └── shp.esm.js │ │ │ ├── pdfjs │ │ │ ├── pdf.js │ │ │ ├── pdf.js.map │ │ │ ├── pdf.sandbox.js │ │ │ ├── pdf.sandbox.js.map │ │ │ ├── pdf.worker.js │ │ │ └── pdf.worker.js.map │ │ │ ├── rxjs │ │ │ ├── rxjs-ajax.min.js │ │ │ ├── rxjs-operators.min.js │ │ │ ├── rxjs-shared.min.js │ │ │ └── rxjs.min.js │ │ │ ├── three │ │ │ ├── FontLoader.js │ │ │ ├── OrbitControls.js │ │ │ ├── Projector.js │ │ │ ├── TextGeometry.js │ │ │ ├── three.module.js │ │ │ └── viewcube.js │ │ │ └── wavesurfer.js │ ├── locales │ │ ├── _.json │ │ ├── az.json │ │ ├── be.json │ │ ├── bg.json │ │ ├── ca.json │ │ ├── cs.json │ │ ├── da.json │ │ ├── de.json │ │ ├── el.json │ │ ├── es.json │ │ ├── et.json │ │ ├── eu.json │ │ ├── fi.json │ │ ├── fr.json │ │ ├── gl.json │ │ ├── hr.json │ │ ├── hu.json │ │ ├── id.json │ │ ├── index.js │ │ ├── is.json │ │ ├── it.json │ │ ├── ja.json │ │ ├── ka.json │ │ ├── ko.json │ │ ├── lt.json │ │ ├── lv.json │ │ ├── mn.json │ │ ├── nb.json │ │ ├── nl.json │ │ ├── no.json │ │ ├── pl.json │ │ ├── pt.json │ │ ├── ro.json │ │ ├── ru.json │ │ ├── script.js │ │ ├── sk.json │ │ ├── sl.json │ │ ├── sr.json │ │ ├── sv.json │ │ ├── th.json │ │ ├── tr.json │ │ ├── uk.json │ │ ├── vi.json │ │ ├── zh.json │ │ └── zh_tw.json │ ├── logo │ │ ├── android-chrome-192x192.png │ │ ├── android-chrome-512x512.png │ │ ├── app_icon.png │ │ ├── apple-touch-icon.png │ │ ├── favicon-16x16.png │ │ ├── favicon-32x32.png │ │ ├── favicon.ico │ │ ├── favicon.svg │ │ ├── mstile-150x150.png │ │ ├── og-image.png │ │ └── safari-pinned-tab.svg │ ├── model │ │ ├── backend.js │ │ ├── chromecast.js │ │ ├── config.d.ts │ │ ├── config.js │ │ ├── plugin.js │ │ └── session.js │ ├── pages │ │ ├── adminpage │ │ │ ├── animate.js │ │ │ ├── component_box-item.js │ │ │ ├── ctrl_about.css │ │ │ ├── ctrl_about.js │ │ │ ├── ctrl_backend.css │ │ │ ├── ctrl_backend.js │ │ │ ├── ctrl_backend_component_authentication.js │ │ │ ├── ctrl_backend_component_storage.js │ │ │ ├── ctrl_backend_state.js │ │ │ ├── ctrl_log.js │ │ │ ├── ctrl_log_audit.js │ │ │ ├── ctrl_log_form.js │ │ │ ├── ctrl_log_viewer.css │ │ │ ├── ctrl_log_viewer.js │ │ │ ├── ctrl_login.css │ │ │ ├── ctrl_login.js │ │ │ ├── ctrl_settings.js │ │ │ ├── ctrl_setup.css │ │ │ ├── ctrl_setup.js │ │ │ ├── decorator.js │ │ │ ├── decorator_admin_only.js │ │ │ ├── decorator_sidemenu.css │ │ │ ├── decorator_sidemenu.js │ │ │ ├── helper_form.js │ │ │ ├── index.css │ │ │ ├── model_admin_session.js │ │ │ ├── model_audit.js │ │ │ ├── model_auth_middleware.js │ │ │ ├── model_backend.js │ │ │ ├── model_config.js │ │ │ ├── model_log.js │ │ │ ├── model_release.js │ │ │ └── model_setup.js │ │ ├── connectpage │ │ │ ├── ctrl_forkme.js │ │ │ ├── ctrl_form.css │ │ │ ├── ctrl_form.js │ │ │ ├── ctrl_form_state.js │ │ │ ├── ctrl_poweredby.js │ │ │ ├── model_backend.js │ │ │ └── model_config.js │ │ ├── ctrl_adminpage.js │ │ ├── ctrl_connectpage.css │ │ ├── ctrl_connectpage.js │ │ ├── ctrl_error.js │ │ ├── ctrl_filespage.css │ │ ├── ctrl_filespage.js │ │ ├── ctrl_homepage.js │ │ ├── ctrl_logout.js │ │ ├── ctrl_notfound.js │ │ ├── ctrl_sharepage.css │ │ ├── ctrl_sharepage.js │ │ ├── ctrl_viewerpage.css │ │ ├── ctrl_viewerpage.js │ │ ├── filespage │ │ │ ├── cache.js │ │ │ ├── ctrl_filesystem.css │ │ │ ├── ctrl_filesystem.js │ │ │ ├── ctrl_frequentlyaccess.css │ │ │ ├── ctrl_frequentlyaccess.js │ │ │ ├── ctrl_newitem.css │ │ │ ├── ctrl_newitem.js │ │ │ ├── ctrl_submenu.css │ │ │ ├── ctrl_submenu.js │ │ │ ├── ctrl_upload.css │ │ │ ├── ctrl_upload.d.ts │ │ │ ├── ctrl_upload.js │ │ │ ├── helper.js │ │ │ ├── modal.css │ │ │ ├── modal_delete.js │ │ │ ├── modal_rename.js │ │ │ ├── modal_share.css │ │ │ ├── modal_share.js │ │ │ ├── modal_tag.css │ │ │ ├── modal_tag.js │ │ │ ├── model_acl.js │ │ │ ├── model_files.js │ │ │ ├── model_virtual_layer.js │ │ │ ├── state_config.js │ │ │ ├── state_newthing.js │ │ │ ├── state_selection.js │ │ │ ├── thing.css │ │ │ ├── thing.d.ts │ │ │ └── thing.js │ │ └── viewerpage │ │ │ ├── application_3d.css │ │ │ ├── application_3d.d.ts │ │ │ ├── application_3d.js │ │ │ ├── application_3d │ │ │ ├── init.js │ │ │ ├── scene_cube.js │ │ │ ├── scene_light.js │ │ │ └── toolbar.js │ │ │ ├── application_audio.css │ │ │ ├── application_audio.d.ts │ │ │ ├── application_audio.js │ │ │ ├── application_downloader.css │ │ │ ├── application_downloader.js │ │ │ ├── application_ebook.css │ │ │ ├── application_ebook.d.ts │ │ │ ├── application_ebook.js │ │ │ ├── application_editor.css │ │ │ ├── application_editor.d.ts │ │ │ ├── application_editor.js │ │ │ ├── application_editor │ │ │ ├── clike.js │ │ │ ├── clojure.js │ │ │ ├── cmake.js │ │ │ ├── commonlisp.js │ │ │ ├── css.js │ │ │ ├── diff.js │ │ │ ├── dockerfile.js │ │ │ ├── elm.js │ │ │ ├── emacs-org.js │ │ │ ├── erlang.js │ │ │ ├── go.js │ │ │ ├── groovy.js │ │ │ ├── htmlmixed.js │ │ │ ├── java.js │ │ │ ├── javascript.js │ │ │ ├── jsx.js │ │ │ ├── keymap_base.js │ │ │ ├── keymap_vim.js │ │ │ ├── lua.js │ │ │ ├── orgmode.js │ │ │ ├── perl.js │ │ │ ├── php.js │ │ │ ├── properties.js │ │ │ ├── python.js │ │ │ ├── r.js │ │ │ ├── ruby.js │ │ │ ├── rust.js │ │ │ ├── sass.js │ │ │ ├── shell.js │ │ │ ├── sparql.js │ │ │ ├── spreadsheet.js │ │ │ ├── sql.js │ │ │ ├── stex.js │ │ │ ├── text.js │ │ │ ├── xml.js │ │ │ ├── yaml-frontmatter.js │ │ │ └── yaml.js │ │ │ ├── application_editor_orgmode.js │ │ │ ├── application_form.css │ │ │ ├── application_form.js │ │ │ ├── application_iframe.css │ │ │ ├── application_iframe.js │ │ │ ├── application_image.css │ │ │ ├── application_image.d.ts │ │ │ ├── application_image.js │ │ │ ├── application_image │ │ │ ├── information.css │ │ │ ├── information.js │ │ │ ├── pagination.css │ │ │ ├── pagination.js │ │ │ └── zoom.js │ │ │ ├── application_map.css │ │ │ ├── application_map.d.ts │ │ │ ├── application_map.js │ │ │ ├── application_pdf.css │ │ │ ├── application_pdf.d.ts │ │ │ ├── application_pdf.js │ │ │ ├── application_skeleton.css │ │ │ ├── application_skeleton.js │ │ │ ├── application_table.css │ │ │ ├── application_table.js │ │ │ ├── application_url.js │ │ │ ├── application_video.css │ │ │ ├── application_video.js │ │ │ ├── common.js │ │ │ ├── common_fab.js │ │ │ ├── common_icon.js │ │ │ ├── common_player.js │ │ │ ├── component_menubar.css │ │ │ ├── component_menubar.js │ │ │ ├── mimetype.js │ │ │ └── model_files.js │ └── sw.js ├── global.d.ts ├── index.backoffice.html ├── index.frontoffice.html ├── package.json ├── tsconfig.json ├── vite.config.js └── vite.setup.js ├── server ├── .assets │ └── emacs │ │ ├── README.md │ │ ├── htmlize.el │ │ └── ox-gfm.el ├── common │ ├── api.go │ ├── app.go │ ├── backend.go │ ├── cache.go │ ├── config.go │ ├── config_state.go │ ├── constants.go │ ├── crypto.go │ ├── debug.go │ ├── default.go │ ├── dummy.go │ ├── error.go │ ├── files.go │ ├── files_all.go │ ├── files_linux.go │ ├── log.go │ ├── mime.go │ ├── plugin.go │ ├── recovery.go │ ├── response.go │ ├── ssl │ │ ├── cert.go │ │ ├── generate.go │ │ ├── index.go │ │ ├── private.go │ │ └── root.go │ ├── token.go │ ├── types.go │ └── utils.go ├── ctrl │ ├── admin.go │ ├── config.go │ ├── documentation.go │ ├── export.go │ ├── files.go │ ├── plugin.go │ ├── report.go │ ├── search.go │ ├── session.go │ ├── share.go │ ├── static.go │ ├── static │ │ ├── 404.html │ │ └── loader.html │ ├── tmpl.go │ └── webdav.go ├── generator │ ├── constants.go │ ├── emacs-el.go │ └── mime.go ├── middleware │ ├── context.go │ ├── http.go │ ├── index.go │ ├── session.go │ └── telemetry.go ├── model │ ├── audit.go │ ├── files.go │ ├── formater │ │ ├── README.md │ │ ├── office.go │ │ ├── pdf.go │ │ └── txt.go │ ├── index.go │ ├── permissions.go │ ├── plugin.go │ ├── share.go │ └── webdav.go ├── plugin │ ├── index.go │ ├── plg_application_3d │ │ ├── Makefile │ │ ├── index_fbx.js │ │ ├── index_gltf.js │ │ ├── index_mesh.js │ │ ├── index_obj.js │ │ ├── index_step.js │ │ ├── index_stl.js │ │ ├── index_svg.js │ │ ├── manifest.json │ │ └── vendor │ │ │ ├── FBXLoader.js │ │ │ ├── GLTFLoader.js │ │ │ ├── OBJLoader.js │ │ │ ├── STLLoader.js │ │ │ ├── SVGLoader.js │ │ │ ├── curves │ │ │ ├── NURBSCurve.js │ │ │ └── NURBSUtils.js │ │ │ ├── libs │ │ │ └── fflate.module.js │ │ │ └── utils │ │ │ └── BufferGeometryUtils.js │ ├── plg_application_dev │ │ ├── Makefile │ │ ├── index.js │ │ ├── loader_symbol.c │ │ └── manifest.json │ ├── plg_application_map │ │ ├── Makefile │ │ ├── constant.js │ │ ├── index_geojson.js │ │ ├── index_gpx.js │ │ ├── index_wms.js │ │ ├── manifest.json │ │ └── plugins │ │ │ └── plugin_grayscale.js │ ├── plg_authenticate_admin │ │ └── index.go │ ├── plg_authenticate_htpasswd │ │ ├── deps │ │ │ └── crypt │ │ │ │ ├── AUTHORS.md │ │ │ │ ├── LICENSE │ │ │ │ ├── README.md │ │ │ │ ├── apr1_crypt │ │ │ │ └── apr1_crypt.go │ │ │ │ ├── common │ │ │ │ ├── base64.go │ │ │ │ ├── doc.go │ │ │ │ └── salt.go │ │ │ │ ├── crypt.go │ │ │ │ ├── md5_crypt │ │ │ │ └── md5_crypt.go │ │ │ │ ├── sha256_crypt │ │ │ │ └── sha256_crypt.go │ │ │ │ └── sha512_crypt │ │ │ │ └── sha512_crypt.go │ │ └── index.go │ ├── plg_authenticate_ldap │ │ └── index.go │ ├── plg_authenticate_local │ │ ├── auth.go │ │ ├── data.go │ │ ├── handler.go │ │ ├── handler.html │ │ ├── index.go │ │ ├── notify.go │ │ ├── service.go │ │ └── utils.go │ ├── plg_authenticate_openid │ │ └── index.go │ ├── plg_authenticate_passthrough │ │ └── index.go │ ├── plg_authenticate_saml │ │ └── index.go │ ├── plg_authorisation_example │ │ └── index.go │ ├── plg_backend_artifactory │ │ └── index.go │ ├── plg_backend_azure │ │ └── index.go │ ├── plg_backend_backblaze │ │ └── index.go │ ├── plg_backend_dav │ │ └── index.go │ ├── plg_backend_dropbox │ │ └── index.go │ ├── plg_backend_ftp │ │ └── index.go │ ├── plg_backend_ftp_only │ │ └── index.go │ ├── plg_backend_gdrive │ │ └── index.go │ ├── plg_backend_git │ │ └── index.go │ ├── plg_backend_ldap │ │ └── index.go │ ├── plg_backend_local │ │ └── index.go │ ├── plg_backend_mysql │ │ └── index.go │ ├── plg_backend_nfs │ │ ├── auth_helper.go │ │ ├── auth_unix.go │ │ └── index.go │ ├── plg_backend_nfs4 │ │ ├── index.go │ │ └── repo │ │ │ ├── README.md │ │ │ ├── internal │ │ │ ├── cleanuper.go │ │ │ ├── nfs4.go │ │ │ ├── nfs4.x │ │ │ ├── nfsconst.go │ │ │ ├── rpc.go │ │ │ ├── rpc.x │ │ │ └── types.go │ │ │ └── nfs4 │ │ │ ├── client.go │ │ │ ├── nfs_err.go │ │ │ └── supervised_conn.go │ ├── plg_backend_nop │ │ └── index.go │ ├── plg_backend_s3 │ │ └── index.go │ ├── plg_backend_samba │ │ └── index.go │ ├── plg_backend_sftp │ │ └── index.go │ ├── plg_backend_storj │ │ └── index.go │ ├── plg_backend_tmp │ │ └── index.go │ ├── plg_backend_url │ │ └── index.go │ ├── plg_backend_webdav │ │ └── index.go │ ├── plg_editor_onlyoffice │ │ └── index.go │ ├── plg_editor_wopi │ │ ├── config.go │ │ ├── handler.go │ │ └── index.go │ ├── plg_handler_console │ │ ├── index.go │ │ ├── index_linux.go │ │ └── src │ │ │ ├── app.css │ │ │ ├── xterm.css │ │ │ └── xterm.js │ ├── plg_handler_mcp │ │ ├── README.md │ │ ├── config │ │ │ └── config.go │ │ ├── handler.go │ │ ├── handler_auth.go │ │ ├── handler_state.go │ │ ├── impl │ │ │ ├── completion.go │ │ │ ├── prompts.go │ │ │ ├── prompts_fs.go │ │ │ ├── resources.go │ │ │ ├── tools.go │ │ │ └── tools_fs.go │ │ ├── index.go │ │ ├── types │ │ │ ├── mcp_completion.go │ │ │ ├── mcp_init.go │ │ │ ├── mcp_notification.go │ │ │ ├── mcp_prompts.go │ │ │ ├── mcp_resources.go │ │ │ ├── mcp_tools.go │ │ │ ├── resources.go │ │ │ ├── rpc.go │ │ │ └── session.go │ │ └── utils │ │ │ ├── cors.go │ │ │ ├── default.go │ │ │ ├── json.go │ │ │ ├── mcp.go │ │ │ └── response.go │ ├── plg_handler_syncthing │ │ └── index.go │ ├── plg_image_ascii │ │ └── index.go │ ├── plg_image_bimg │ │ └── index.go │ ├── plg_image_c │ │ ├── image_gif.c │ │ ├── image_gif.go │ │ ├── image_gif.h │ │ ├── image_gif_vendor.h │ │ ├── image_jpeg.c │ │ ├── image_jpeg.h │ │ ├── image_jpeg_freebsd.go │ │ ├── image_jpeg_linux.go │ │ ├── image_png.c │ │ ├── image_png.h │ │ ├── image_png_freebsd.go │ │ ├── image_png_linux.go │ │ ├── image_psd.c │ │ ├── image_psd.go │ │ ├── image_psd.h │ │ ├── image_psd_vendor.h │ │ ├── image_raw.c │ │ ├── image_raw.h │ │ ├── image_raw_freebsd.go │ │ ├── image_raw_linux.go │ │ ├── image_webp.c │ │ ├── image_webp.go │ │ ├── image_webp.h │ │ ├── index.go │ │ └── utils.h │ ├── plg_image_golang │ │ └── index.go │ ├── plg_image_light │ │ ├── deps │ │ │ ├── README.md │ │ │ ├── create_libresize.sh │ │ │ ├── create_libtranscode.sh │ │ │ └── src │ │ │ │ ├── libresize.c │ │ │ │ ├── libresize.h │ │ │ │ ├── libresize_test.c │ │ │ │ ├── libtranscode.c │ │ │ │ ├── libtranscode.h │ │ │ │ └── libtranscode_test.c │ │ ├── index.go │ │ ├── install.sh │ │ ├── lib_resize.go │ │ ├── lib_resize_linux_amd64.go │ │ ├── lib_resize_linux_arm.go │ │ ├── lib_transcode.go │ │ ├── lib_transcode_linux_amd64.go │ │ └── lib_transcode_linux_arm.go │ ├── plg_image_transcode │ │ ├── index.go │ │ ├── transcode_bmp.go │ │ ├── transcode_dicom.go │ │ ├── transcode_svg.go │ │ └── transcode_tiff.go │ ├── plg_override_actiondelete │ │ ├── assets │ │ │ └── pages │ │ │ │ └── filespage │ │ │ │ └── thing.js │ │ └── index.go │ ├── plg_override_download │ │ ├── README.md │ │ ├── assets │ │ │ └── pages │ │ │ │ └── filespage │ │ │ │ └── thing.js │ │ └── index.go │ ├── plg_search_example │ │ └── index.go │ ├── plg_search_sqlitefts │ │ ├── converter │ │ │ └── index.go │ │ ├── crawler │ │ │ ├── configuration.go │ │ │ ├── daemon.go │ │ │ ├── daemon_state.go │ │ │ ├── events.go │ │ │ ├── phase.go │ │ │ ├── phase_explore.go │ │ │ ├── phase_indexing.go │ │ │ ├── phase_maintain.go │ │ │ ├── phase_utils.go │ │ │ └── types.go │ │ ├── index.go │ │ ├── indexer │ │ │ ├── error.go │ │ │ ├── index.go │ │ │ └── query.go │ │ └── query.go │ ├── plg_search_stateless │ │ ├── config.go │ │ ├── index.go │ │ └── scoring.go │ ├── plg_security_scanner │ │ └── index.go │ ├── plg_security_svg │ │ └── index.go │ ├── plg_starter_http │ │ └── index.go │ ├── plg_starter_http2 │ │ └── index.go │ ├── plg_starter_https │ │ └── index.go │ ├── plg_starter_tor │ │ └── index.go │ ├── plg_video_thumbnail │ │ └── index.go │ └── plg_video_transcoder │ │ └── index.go └── routes.go └── webpack.config.js /.assets/img/customisation_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/img/customisation_1.png -------------------------------------------------------------------------------- /.assets/img/orgmode.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/img/orgmode.gif -------------------------------------------------------------------------------- /.assets/raw/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | convert -delay 100 -loop 0 navigation_*.png navigation.gif 3 | convert -delay 100 -loop 0 orgmode_*.png orgmode.gif 4 | convert -delay 100 -loop 0 photo_management_*.png photo_management.gif 5 | -------------------------------------------------------------------------------- /.assets/raw/navigation_00001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00001.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00002.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00003.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00004.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00005.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00006.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00007.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00008.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00009.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00010.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00011.png -------------------------------------------------------------------------------- /.assets/raw/navigation_00012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/navigation_00012.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00001.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00002.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00003.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00004.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00005.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00006.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00007.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00008.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00009.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00010.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00011.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00011.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00012.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00012.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00013.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00013.png -------------------------------------------------------------------------------- /.assets/raw/orgmode_00014.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/orgmode_00014.png -------------------------------------------------------------------------------- /.assets/raw/photo.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo.xcf -------------------------------------------------------------------------------- /.assets/raw/photo_management_0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0001.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0002.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0003.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0004.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0005.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0006.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0006.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0007.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0007.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0008.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0008.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0009.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0009.png -------------------------------------------------------------------------------- /.assets/raw/photo_management_0010.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/.assets/raw/photo_management_0010.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["react", "es2015", "stage-2"], 3 | "plugins": ["transform-decorators-legacy", "syntax-dynamic-import"] 4 | } -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | [*] 4 | indent_style = space 5 | indent_size = 4 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.go] 12 | indent_size = 4 13 | indent_style = tab 14 | 15 | [Makefile] 16 | indent_style = tab -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | open_collective: filestash 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug 3 | about: Report a bug 4 | title: "[bug] " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | # Description of the bug 11 | 12 | 13 | 14 | # Step by step instructions to reproduce the bug 15 | 16 | 17 | 18 | # Can you replicate that error from the demo? 19 | 20 | 24 | 25 | # Observed behavior 26 | 27 | 28 | 29 | # Expected behavior 30 | 31 | 32 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature Request 3 | about: Request for a new feature 4 | title: "[Feature Request] " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/support.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Support 3 | about: Technical support is only available on IRC 4 | title: "[support] DO NOT CREATE A SUPPORT TICKET FROM GITHUB" 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Please, don't create tickets on github for support. Instead, you can either: 11 | - visit the community support on libera.chat #filestash. A searchable archive is available at https://support.filestash.app If you don't already have an IRC client, you can try this link: https://kiwiirc.com/nextclient/#irc://irc.libera.chat/#filestash?nick=guest?? 12 | - register for enterprise support at https://www.filestash.app/pricing/#support 13 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .sass-cache 3 | dist/ 4 | *_generated.go 5 | test/ 6 | *.a 7 | *.o 8 | *.bin 9 | .DS_Store 10 | package-lock.json 11 | \#*\# 12 | .\#* 13 | *.log 14 | *~ 15 | *.swp 16 | *.swo 17 | .tern-port 18 | .tern-project.js 19 | *_test.go 20 | cover.* 21 | www 22 | .gitignore 23 | 24 | 25 | # frontend 26 | public/**/*.test.js 27 | public/**/__snapshots__ 28 | public/jest.setup.js 29 | public/package.json 30 | public/README.org 31 | 32 | filestash-enterprise -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make build_init 3 | make build_frontend 4 | make build_backend 5 | 6 | build_init: 7 | go get ./... 8 | go generate -x ./server/... 9 | 10 | build_frontend: 11 | make build_frontend_old 12 | cd public && make compress 13 | 14 | build_frontend_old: 15 | NODE_ENV=production npm run build 16 | mkdir -p ./server/ctrl/static/www/canary/ 17 | cp -R ./public/assets ./server/ctrl/static/www/canary/ 18 | cp -R ./public/*.html ./server/ctrl/static/www/canary/ 19 | 20 | build_backend: 21 | CGO_ENABLED=1 go build --tags "fts5" -o dist/filestash cmd/main.go 22 | 23 | build_backend_arm64: 24 | CGO_ENABLED=1 GOOS=linux GOARCH=arm GOARM=7 CC=arm-linux-gnueabihf-gcc go build -o dist/filestash cmd/main.go 25 | 26 | build_backend_amd64: 27 | GOOS=linux CGO_ENABLED=1 GOARCH=amd64 CC=gcc go build -o dist/filestash cmd/main.go 28 | 29 | clean_frontend: 30 | rm -rf server/ctrl/static/www/ 31 | -------------------------------------------------------------------------------- /client/assets/css/videojs-custom.css: -------------------------------------------------------------------------------- 1 | .video-js{outline: none;} 2 | 3 | .video-js .vjs-big-play-button:before, .video-js .vjs-control:before, .video-js .vjs-modal-dialog, .vjs-modal-dialog .vjs-modal-dialog-content { 4 | position: absolute; 5 | top: 0; 6 | left: 0; 7 | width: 100%; 8 | height: 100%; } 9 | 10 | .video-js .vjs-big-play-button:before, .video-js .vjs-control:before { 11 | text-align: center; } 12 | -------------------------------------------------------------------------------- /client/assets/fonts/SourceCodePro-Regular-400-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/fonts/SourceCodePro-Regular-400-latin-ext.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/SourceCodePro-Regular-400-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/fonts/SourceCodePro-Regular-400-latin.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/SourceCodePro-Semibold-600-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/fonts/SourceCodePro-Semibold-600-latin-ext.woff2 -------------------------------------------------------------------------------- /client/assets/fonts/SourceCodePro-Semibold-600-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/fonts/SourceCodePro-Semibold-600-latin.woff2 -------------------------------------------------------------------------------- /client/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/icons/music.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/icons/music.png -------------------------------------------------------------------------------- /client/assets/icons/photo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/icons/photo.png -------------------------------------------------------------------------------- /client/assets/icons/placeholder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/icons/placeholder.png -------------------------------------------------------------------------------- /client/assets/icons/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /client/assets/icons/video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/icons/video.png -------------------------------------------------------------------------------- /client/assets/img/arrow_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/arrow_left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/arrow_left_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/arrow_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/arrow_right_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/arrow_top.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/bucket.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/calendar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/calendar_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/camera.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/close_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/copy.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/deadline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/download.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/download_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/dropbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/img/dropbox.png -------------------------------------------------------------------------------- /client/assets/img/error.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /client/assets/img/google-drive.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/img/google-drive.png -------------------------------------------------------------------------------- /client/assets/img/grid.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /client/assets/img/info.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/assets/img/loader.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/assets/img/loader_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /client/assets/img/location.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/more.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/pause.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/power.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/assets/img/schedule.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/search_dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/sort.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /client/assets/img/stop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/assets/img/upload_white.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/assets/img/volume.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /client/assets/img/volume_low.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/img/volume_mute.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /client/assets/logo/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/android-chrome-192x192.png -------------------------------------------------------------------------------- /client/assets/logo/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/android-chrome-512x512.png -------------------------------------------------------------------------------- /client/assets/logo/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/app_icon.png -------------------------------------------------------------------------------- /client/assets/logo/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/apple-touch-icon.png -------------------------------------------------------------------------------- /client/assets/logo/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/favicon-16x16.png -------------------------------------------------------------------------------- /client/assets/logo/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/favicon-32x32.png -------------------------------------------------------------------------------- /client/assets/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/favicon.ico -------------------------------------------------------------------------------- /client/assets/logo/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/mstile-150x150.png -------------------------------------------------------------------------------- /client/assets/logo/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/assets/logo/og-image.png -------------------------------------------------------------------------------- /client/components/alert.scss: -------------------------------------------------------------------------------- 1 | .alert { 2 | background: var(--bg-color); 3 | border-radius: 5px; 4 | padding: 20px; 5 | margin-top: 20px; 6 | margin-bottom: 20px; 7 | border: 1px solid rgba(0,0,0,0.05); 8 | 9 | ol, ul { 10 | margin: 5px 0; 11 | padding: 0 20px; 12 | } 13 | 14 | &.success{ 15 | background: var(--success); 16 | } 17 | &.error{ 18 | background: var(--error); 19 | color: var(--bg-color); 20 | } 21 | 22 | img{ 23 | max-width: 100%; 24 | border-radius: 5px; 25 | border: 10px solid white; 26 | box-sizing: border-box; 27 | margin-top: 5px; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/components/button.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | 3 | import "./button.scss"; 4 | 5 | export function Button({ theme = "", children = null, className = "", ...props }) { 6 | return ( 7 | 10 | ); 11 | } 12 | -------------------------------------------------------------------------------- /client/components/button.scss: -------------------------------------------------------------------------------- 1 | button{ 2 | border: none; 3 | margin: 0; 4 | padding: 6px; 5 | width: 100%; 6 | display: inline-block; 7 | outline: none; 8 | cursor: pointer; 9 | font-size: inherit; 10 | border-radius: 2px; 11 | color: inherit; 12 | background: inherit; 13 | 14 | &.primary{ 15 | background: var(--primary); 16 | color: white; 17 | } 18 | &.emphasis{ 19 | background: var(--emphasis); 20 | color: white; 21 | } 22 | &.dark{ 23 | background: var(--dark); 24 | color: white; 25 | } 26 | } 27 | 28 | .touch-no button { 29 | &.dark:hover, &.emphasis:hover, &.primary:hover { 30 | filter: brightness(95%); 31 | transition: 0.2s ease all; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /client/components/card.scss: -------------------------------------------------------------------------------- 1 | .box{ 2 | padding: 10px; 3 | cursor: pointer; 4 | margin: 3px 0; 5 | overflow: hidden; 6 | position: relative; 7 | } 8 | -------------------------------------------------------------------------------- /client/components/container.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./container.scss"; 3 | 4 | export class Container extends React.Component { 5 | constructor(props) { 6 | super(props); 7 | } 8 | render() { 9 | const style = this.props.maxWidth ? { maxWidth: this.props.maxWidth } : {}; 10 | let className = "component_container"; 11 | if (this.props.className) className += " " + this.props.className; 12 | return ( 13 |
14 | {this.props.children} 15 |
16 | ); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /client/components/container.scss: -------------------------------------------------------------------------------- 1 | .component_container{ 2 | width: 95%; 3 | max-width: 800px; 4 | margin: 0 auto; 5 | padding: 10px; 6 | } 7 | -------------------------------------------------------------------------------- /client/components/fab.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import "./fab.scss"; 3 | 4 | export function Fab(props) { 5 | return ( 6 |
7 |
8 | {props.children} 9 |
10 |
11 | ); 12 | } 13 | -------------------------------------------------------------------------------- /client/components/fab.scss: -------------------------------------------------------------------------------- 1 | .component_fab{ 2 | position: fixed; 3 | bottom: 20px; 4 | right: 20px; 5 | z-index: 2; 6 | .content{ 7 | height: 25px; 8 | width: 25px; 9 | padding: 13px; 10 | border-radius: 50%; 11 | background: var(--color); 12 | box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px; 13 | z-index: 1000; 14 | cursor: pointer; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /client/components/icon.scss: -------------------------------------------------------------------------------- 1 | .component_icon{ 2 | vertical-align: bottom; 3 | max-height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /client/components/loader.scss: -------------------------------------------------------------------------------- 1 | .component_loader{ 2 | text-align: center; 3 | margin: 50px auto 0 auto; 4 | } 5 | -------------------------------------------------------------------------------- /client/components/popup.scss: -------------------------------------------------------------------------------- 1 | .component_popup{ 2 | .popup--content{ 3 | font-size: 1.1em; 4 | margin: 0; 5 | p {margin: 0;} 6 | .modal-error-message{font-size: 15px;} 7 | } 8 | .buttons{ 9 | margin: 15px -20px 0 -20px; 10 | display: flex; 11 | 12 | > div { 13 | display: flex; 14 | width: 100%; 15 | } 16 | [type="submit"]{ 17 | border-radius: 10px 0 0; 18 | } 19 | > button{ 20 | width: 50%; 21 | margin-left: auto; 22 | } 23 | button{ 24 | text-transform: uppercase; 25 | } 26 | } 27 | .modal-error-message{ 28 | color: var(--error); 29 | } 30 | .center{text-align: center;} 31 | } 32 | -------------------------------------------------------------------------------- /client/components/textarea.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/client/components/textarea.woff -------------------------------------------------------------------------------- /client/components/video.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Icon } from "./"; 3 | import "./video.scss"; 4 | 5 | export class Video extends React.Component { 6 | constructor(props) { 7 | super(props); 8 | } 9 | 10 | render() { 11 | return ( 12 |
13 |
14 | 15 |
16 |
17 | ); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /client/components/video.scss: -------------------------------------------------------------------------------- 1 | .component_video{ 2 | position: fixed; 3 | bottom: 10px; 4 | right: 10px; 5 | width: 300px; 6 | height: 200px; 7 | background: var(--super-light); 8 | border: 1px solid #e2e2e2; 9 | border-radius: 2px; 10 | 11 | .loader{ 12 | text-align: center; 13 | margin-top: 30px; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /client/helpers/bcrypt.js: -------------------------------------------------------------------------------- 1 | import bcrypt from "bcryptjs"; 2 | 3 | const ROUND = 5; 4 | 5 | export function bcrypt_password(password) { 6 | return new Promise((done, error) => { 7 | bcrypt.hash(password, ROUND, (err, hash) => { 8 | if (err) return error(err); 9 | done(hash); 10 | }); 11 | }); 12 | } 13 | -------------------------------------------------------------------------------- /client/helpers/cache_state.js: -------------------------------------------------------------------------------- 1 | import { Session } from "../model"; 2 | 3 | let backendID = null; 4 | 5 | export function currentShare() { 6 | return findParams("share"); 7 | } 8 | 9 | export function currentBackend() { 10 | return backendID || ""; 11 | } 12 | 13 | export function findParams(p) { 14 | return new window.URL(location.href).searchParams.get(p) || ""; 15 | } 16 | 17 | export function setup_cache_state(_backendID = null) { 18 | if (_backendID !== null) { 19 | backendID = _backendID; 20 | return; 21 | } 22 | return Session.currentUser().then((r) => { 23 | backendID = r["backendID"] 24 | }).catch(() => backendID = null); 25 | } 26 | -------------------------------------------------------------------------------- /client/helpers/crypto.js: -------------------------------------------------------------------------------- 1 | import Aesjs from "aes-js"; 2 | 3 | export function encrypt(obj, key) { 4 | const textBytes = Aesjs.utils.utf8.toBytes(JSON.stringify(obj)); 5 | const keyBytes = Aesjs.padding.pkcs7.pad(Aesjs.utils.utf8.toBytes(key)); 6 | return Aesjs.utils.hex.fromBytes( 7 | new Aesjs.ModeOfOperation.ctr(keyBytes, new Aesjs.Counter(5)).encrypt(textBytes), 8 | ); 9 | } 10 | 11 | export function decrypt(text, key) { 12 | const textBytes = Aesjs.utils.hex.toBytes(text); 13 | const keyBytes = Aesjs.padding.pkcs7.pad(Aesjs.utils.utf8.toBytes(key)); 14 | return JSON.parse(Aesjs.utils.utf8.fromBytes( 15 | new Aesjs.ModeOfOperation.ctr(keyBytes, new Aesjs.Counter(5)).decrypt(textBytes), 16 | )); 17 | } 18 | -------------------------------------------------------------------------------- /client/helpers/events.js: -------------------------------------------------------------------------------- 1 | function Event() { 2 | this.fns = []; 3 | } 4 | Event.prototype.subscribe = function(name, fn) { 5 | if (!name || typeof fn !== "function") return; 6 | this.fns.push({ key: name, fn: fn }); 7 | }; 8 | Event.prototype.unsubscribe = function(name) { 9 | this.fns = this.fns.filter((data) => { 10 | return data.key === name ? false : true; 11 | }); 12 | }; 13 | Event.prototype.emit = function(name, payload) { 14 | this.fns.map((data) => { 15 | if (data.key === name) data.fn(payload); 16 | }); 17 | }; 18 | 19 | export const event = new Event(); 20 | -------------------------------------------------------------------------------- /client/helpers/format.js: -------------------------------------------------------------------------------- 1 | export function formatTimecode(seconds) { 2 | return String(parseInt(seconds / 60)).padStart(2, "0") + 3 | ":"+ 4 | String(parseInt(seconds % 60)).padStart(2, "0"); 5 | } 6 | -------------------------------------------------------------------------------- /client/helpers/memory.js: -------------------------------------------------------------------------------- 1 | function Memory() { 2 | const data = {}; 3 | 4 | return { 5 | get: function(key) { 6 | if (data[key] === undefined) return null; 7 | return data[key]; 8 | }, 9 | set: function(key, value) { 10 | data[key] = value; 11 | }, 12 | all: function() { 13 | return data; 14 | }, 15 | }; 16 | } 17 | 18 | 19 | export const memory = new Memory(); 20 | -------------------------------------------------------------------------------- /client/helpers/notify.js: -------------------------------------------------------------------------------- 1 | const Message = function() { 2 | let fn = null; 3 | 4 | return { 5 | send: function(text, type) { 6 | if (["info", "success", "error"].indexOf(type) === -1) { 7 | type = "info"; 8 | } 9 | if (!fn) { 10 | return window.setTimeout(() => this.send(text, type), 50); 11 | } 12 | fn(text, type); 13 | return Promise.resolve(); 14 | }, 15 | subscribe: function(_fn) { 16 | fn = _fn; 17 | }, 18 | }; 19 | }; 20 | 21 | export const notify = new Message(); 22 | -------------------------------------------------------------------------------- /client/helpers/random.js: -------------------------------------------------------------------------------- 1 | export function gid(prefix) { 2 | let id = prefix !== undefined ? prefix : ""; 3 | id += new Date().getTime().toString(32); 4 | id += parseInt(Math.random()*Math.pow(10, 16)).toString(32); 5 | return id; 6 | } 7 | 8 | const alphabet = [ 9 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", 10 | "q", "r", "s", "t", "u", "v", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", 11 | "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 12 | "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 13 | ]; 14 | const alphabet_size = alphabet.length; 15 | 16 | export function randomString(size = 16) { 17 | let str = ""; 18 | for (let i=0; i { 17 | window.localStorage.setItem("settings", JSON.stringify(d)); 18 | }, 500); 19 | } 20 | -------------------------------------------------------------------------------- /client/helpers/upload.js: -------------------------------------------------------------------------------- 1 | const Upload = function() { 2 | let fn = null; 3 | 4 | return { 5 | add: function(path, files) { 6 | if (!fn) { 7 | return window.setTimeout(() => this.add(path, files), 50); 8 | } 9 | fn(path, files); 10 | return Promise.resolve(); 11 | }, 12 | subscribe: function(_fn) { 13 | fn = _fn; 14 | }, 15 | }; 16 | }; 17 | 18 | export const upload = new Upload(); 19 | -------------------------------------------------------------------------------- /client/locales/index.js: -------------------------------------------------------------------------------- 1 | export function t(str = "", replacementString, requestedKey) { 2 | const calculatedKey = str.toUpperCase() 3 | .replace(/ /g, "_") 4 | .replace(/[^a-zA-Z0-9\-\_\*\{\}\?]/g, "") 5 | .replace(/\_+$/, ""); 6 | const value = requestedKey === undefined ? 7 | window.LNG && window.LNG[calculatedKey] : 8 | window.LNG && window.LNG[requestedKey]; 9 | return reformat( 10 | value || str || "", 11 | str, 12 | ).replace("{{VALUE}}", replacementString); 13 | } 14 | 15 | function reformat(translated, initial) { 16 | if (initial[0] && initial[0].toLowerCase() === initial[0]) { 17 | return translated || ""; 18 | } 19 | return (translated[0] && translated[0].toUpperCase() + translated.substring(1)) || ""; 20 | } 21 | 22 | export default t; 23 | -------------------------------------------------------------------------------- /client/model/admin.js: -------------------------------------------------------------------------------- 1 | import { http_post, http_get } from "../helpers"; 2 | 3 | export const Admin = { 4 | login: function(password = "") { 5 | return http_post("/admin/api/session", { password: password }); 6 | }, 7 | isAdmin: function() { 8 | return http_get("/admin/api/session").then((res) => res.result); 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /client/model/audit.js: -------------------------------------------------------------------------------- 1 | import { http_get } from "../helpers/"; 2 | 3 | class AuditManager { 4 | get(searchParams, abort) { 5 | const p = new URLSearchParams(); 6 | Object.keys(searchParams).map((key) => { 7 | p.set(key, searchParams[key]); 8 | }); 9 | const res = http_get("/admin/api/audit?" + p.toString(), "json", { abort }) 10 | .then((res) => [res.result.form, res.result.render]); 11 | return res; 12 | } 13 | } 14 | 15 | export const Audit = new AuditManager(); 16 | -------------------------------------------------------------------------------- /client/model/index.js: -------------------------------------------------------------------------------- 1 | export { Files } from "./files"; 2 | export { Session } from "./session"; 3 | export { Share } from "./share"; 4 | export { Config, Backend, Middleware } from "./config"; 5 | export { Log } from "./log"; 6 | export { Admin } from "./admin"; 7 | export { Audit } from "./audit"; 8 | export { Tags } from "./tags"; 9 | export { Chromecast } from "./chromecast"; 10 | -------------------------------------------------------------------------------- /client/pages/adminpage/about.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from "react"; 2 | import { Redirect } from "react-router-dom"; 3 | import { Loader } from "../../components/"; 4 | 5 | import "./about.scss"; 6 | 7 | export function AboutPage() { 8 | useEffect(() => { 9 | const controller = new AbortController(); 10 | fetch("/about", { signal: controller.signal }) 11 | .then((r) => r.text()) 12 | .then((r) => { 13 | const a = document.createElement("html") 14 | a.innerHTML = r; 15 | document.getElementById("about-page").innerHTML = a.querySelector("table").outerHTML; 16 | }); 17 | return () => controller.abort(); 18 | }, []) 19 | 20 | return ( 21 |
22 | 23 |
24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /client/pages/adminpage/about.scss: -------------------------------------------------------------------------------- 1 | #about-page { 2 | padding-top: 50px; 3 | overflow-x: auto; 4 | table td { 5 | min-width: 100px; 6 | padding: 10px 0; 7 | } 8 | .small { font-size: 0.9rem; } 9 | } 10 | -------------------------------------------------------------------------------- /client/pages/adminpage/home.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { Redirect } from "react-router-dom"; 3 | 4 | export function HomePage() { 5 | return ( ); 6 | } 7 | -------------------------------------------------------------------------------- /client/pages/adminpage/index.js: -------------------------------------------------------------------------------- 1 | export { HomePage } from "./home"; 2 | export { BackendPage } from "./backend"; 3 | export { SettingsPage } from "./settings"; 4 | export { AboutPage } from "./about"; 5 | export { LogPage } from "./logger"; 6 | 7 | export { SetupPage } from "./setup"; 8 | export { LoginPage } from "./loginpage"; 9 | -------------------------------------------------------------------------------- /client/pages/adminpage/logger.scss: -------------------------------------------------------------------------------- 1 | .component_logpage{ 2 | button{ 3 | width: inherit; 4 | float: right; 5 | margin-top: 5px; 6 | padding-left: 20px; 7 | padding-right: 20px; 8 | } 9 | } 10 | 11 | .component_audit { 12 | table { 13 | width: 100%; 14 | text-align: left; 15 | border-collapse: collapse; 16 | 17 | th, td { 18 | border-bottom: 2px solid rgba(0, 0, 0, 0.05); 19 | padding: 10px 0 10px 10px; 20 | } 21 | th { opacity: 0.6; } 22 | 23 | tbody { font-size: 0.95rem; } 24 | thead { text-transform: capitalize; } 25 | } 26 | 27 | .component_icon { height: 50px; margin-top: 20px; } 28 | 29 | .flex { 30 | display: flex; 31 | justify-content: space-between; 32 | .alert { margin: 5px 0 15px 0; } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /client/pages/connectpage/index.js: -------------------------------------------------------------------------------- 1 | export { ForkMe, PoweredByFilestash } from "./forkme"; 2 | export { Form } from "./form"; 3 | -------------------------------------------------------------------------------- /client/pages/error.scss: -------------------------------------------------------------------------------- 1 | .error-page{ 2 | width: 80%; 3 | max-width: 600px; 4 | margin: 50px auto 0 auto; 5 | flex-direction: column; 6 | 7 | h1{margin: 5px 0; font-size: 3.1em;} 8 | h2{margin: 10px 0; font-weight: normal; opacity: 0.9; font-weight: 100; cursor:pointer;} 9 | code{margin-top: 20px; display: block; background:rgba(255,255,255,0.3);padding: 10px; border: 2px dashed rgba(0,0,0,0.1);} 10 | p{font-style: italic;} 11 | a{border-bottom: 1px dashed;} 12 | } 13 | 14 | .backnav { 15 | font-weight: 100; 16 | .component_icon { 17 | height: 23px; 18 | margin-right: -3px; 19 | vertical-align: middle; 20 | } 21 | display: inline-block; 22 | padding: 10px 5px; 23 | } 24 | 25 | .dark-mode { 26 | .error-page, .backnav { 27 | color: rgba(255,255,255,0.8); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /client/pages/filespage/index.js: -------------------------------------------------------------------------------- 1 | export { FileSystem } from "./filesystem"; 2 | export { Submenu } from "./submenu"; 3 | export { BreadCrumbTargettable as BreadCrumb } from "./breadcrumb"; 4 | export { FrequentlyAccess } from "./frequently_access"; 5 | export { Sidebar } from "./sidebar"; 6 | -------------------------------------------------------------------------------- /client/pages/index.js: -------------------------------------------------------------------------------- 1 | export { HomePage } from "./homepage"; 2 | export { SharePage } from "./sharepage"; 3 | export { ConnectPage } from "./connectpage"; 4 | export { LogoutPage } from "./logout"; 5 | export { NotFoundPage } from "./notfoundpage"; 6 | export { FilesPage } from "./filespage"; 7 | export { ViewerPage } from "./viewerpage"; 8 | export { TagsPage } from "./tagspage"; 9 | -------------------------------------------------------------------------------- /client/pages/logout.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from "react"; 2 | 3 | import { Session } from "../model/"; 4 | import { Loader, ErrorPage } from "../components/"; 5 | import { cache } from "../helpers/"; 6 | 7 | function LogoutPageComponent({ error, history }) { 8 | useEffect(() => { 9 | Session.logout().then((res) => { 10 | cache.destroy(); 11 | delete window.BEARER_TOKEN; 12 | window.CONFIG["logout"] ? 13 | location.href = CONFIG["logout"] : 14 | history.push("/"); 15 | }).catch((err) => error(err)); 16 | }, []); 17 | 18 | return ( 19 |
20 | ); 21 | } 22 | 23 | export const LogoutPage = ErrorPage(LogoutPageComponent); 24 | -------------------------------------------------------------------------------- /client/pages/sharepage.scss: -------------------------------------------------------------------------------- 1 | @import "../assets/css/mixin.scss"; 2 | 3 | .sharepage_component { 4 | @include inlinedInputWithSubmit(); 5 | .error{ 6 | animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; 7 | transform: translate3d(0, 0, 0); 8 | backface-visibility: hidden; 9 | perspective: 1000px; 10 | } 11 | animation: 0.2s ease-out 0s 1 enterZoomIn; 12 | } 13 | 14 | 15 | @keyframes enterZoomIn { 16 | 0% { 17 | transform: scale(1.1) 18 | } 19 | 100% { 20 | transform: scale(1); 21 | } 22 | } 23 | 24 | @keyframes shake { 25 | 10%, 90% { 26 | transform: translate3d(-1px, 0, 0); 27 | } 28 | 29 | 20%, 80% { 30 | transform: translate3d(2px, 0, 0); 31 | } 32 | 33 | 30%, 50%, 70% { 34 | transform: translate3d(-4px, 0, 0); 35 | } 36 | 37 | 40%, 60% { 38 | transform: translate3d(4px, 0, 0); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /client/pages/viewerpage/appframe.scss: -------------------------------------------------------------------------------- 1 | body:not(.dark-mode) .component_appframe { 2 | background: #525659; 3 | } 4 | 5 | .component_appframe { 6 | text-align: center; 7 | width: 100%; 8 | 9 | iframe { 10 | width: 100%; 11 | height: 100%; 12 | border: none; 13 | } 14 | .error { 15 | color: white; 16 | font-size: 17px; 17 | margin-top: 10px; 18 | font-family: monospace; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/pages/viewerpage/ebookviewer.scss: -------------------------------------------------------------------------------- 1 | .component_ebookviewer{ 2 | display: flex; 3 | flex-direction: column; 4 | flex: 1; 5 | width: 100%; 6 | flex-grow: 1; 7 | 8 | .ebookviewer_container{ 9 | display: flex; 10 | flex-grow: 1; 11 | min-height: 0; 12 | .epub-container { 13 | background: var(--super-light); 14 | padding-top: 50px; 15 | padding-bottom: 50px; 16 | box-sizing: border-box; 17 | overflow-x: hidden!important; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/clike.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/clike/clike"; 2 | CodeMirror.__mode = "clike"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/clojure.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/clojure/clojure"; 2 | CodeMirror.__mode = "clojure"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/cmake.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/cmake/cmake"; 2 | CodeMirror.__mode = "cmake"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/commonlisp.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/commonlisp/commonlisp"; 2 | CodeMirror.__mode = "commonlisp"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/css.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/css/css"; 2 | CodeMirror.__mode = "css"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/diff.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/diff/diff"; 2 | CodeMirror.__mode = "diff"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/dockerfile.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/dockerfile/dockerfile"; 2 | CodeMirror.__mode = "dockerfile"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/elm.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/elm/elm"; 2 | CodeMirror.__mode = "elm"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/erlang.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/erlang/erlang"; 2 | CodeMirror.__mode = "erlang"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/go.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/go/go"; 2 | CodeMirror.__mode = "go"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/htmlmixed.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/htmlmixed/htmlmixed"; 2 | CodeMirror.__mode = "htmlmixed"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/javascript.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/javascript/javascript"; 2 | CodeMirror.__mode = "javascript"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/jsx.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/jsx/jsx"; 2 | CodeMirror.__mode = "jsx"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/keymap_base.js: -------------------------------------------------------------------------------- 1 | import "codemirror/keymap/sublime.js"; 2 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/keymap_vim.js: -------------------------------------------------------------------------------- 1 | import "codemirror/keymap/vim.js"; 2 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/lua.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/lua/lua"; 2 | CodeMirror.__mode = "lua"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/perl.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/perl/perl"; 2 | CodeMirror.__mode = "perl"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/php.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/php/php"; 2 | CodeMirror.__mode = "php"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/properties.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/properties/properties"; 2 | CodeMirror.__mode = "properties"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/python.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/python/python"; 2 | CodeMirror.__mode = "python"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/r.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/r/r"; 2 | CodeMirror.__mode = "r"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/ruby.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/ruby/ruby"; 2 | CodeMirror.__mode = "ruby"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/rust.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/rust/rust"; 2 | CodeMirror.__mode = "rust"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/sass.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/sass/sass"; 2 | CodeMirror.__mode = "sass"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/shell.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/shell/shell"; 2 | CodeMirror.__mode = "shell"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/sparql.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/sparql/sparql"; 2 | CodeMirror.__mode = "sparql"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/spreadsheet.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/spreadsheet/spreadsheet"; 2 | CodeMirror.__mode = "spreadsheet"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/sql.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/sql/sql"; 2 | CodeMirror.__mode = "sql"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/stex.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/stex/stex"; 2 | CodeMirror.__mode = "stex"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/text.js: -------------------------------------------------------------------------------- 1 | export default CodeMirror; 2 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/xml.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/xml/xml"; 2 | CodeMirror.__mode = "xml"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/yaml-frontmatter.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/gfm/gfm"; 2 | import "codemirror/mode/yaml-frontmatter/yaml-frontmatter"; 3 | CodeMirror.__mode = "yaml-frontmatter"; 4 | export default CodeMirror; 5 | -------------------------------------------------------------------------------- /client/pages/viewerpage/editor/yaml.js: -------------------------------------------------------------------------------- 1 | import "codemirror/mode/yaml/yaml"; 2 | CodeMirror.__mode = "yaml"; 3 | export default CodeMirror; 4 | -------------------------------------------------------------------------------- /client/pages/viewerpage/index.js: -------------------------------------------------------------------------------- 1 | export { FileDownloader } from "./filedownloader"; 2 | export { ImageViewer } from "./imageviewer"; 3 | export { PDFViewer } from "./pdfviewer"; 4 | export { FormViewer } from "./formviewer"; 5 | // Those are commented because they will be delivered as a separate chunk 6 | // export { VideoPlayer } from "./videoplayer"; 7 | // export { IDE } from "./ide"; 8 | // export { AudioPlayer } from "./audioplayer"; 9 | -------------------------------------------------------------------------------- /client/pages/viewerpage/pdfviewer.scss: -------------------------------------------------------------------------------- 1 | body:not(.dark-mode) .component_pdfviewer .pdfviewer_container { 2 | background: #525659; 3 | } 4 | 5 | .component_pdfviewer{ 6 | display: flex; 7 | flex-direction: column; 8 | flex: 1; 9 | width: 100%; 10 | flex-grow: 1; 11 | 12 | .pdfviewer_container { 13 | text-align: center; 14 | height: 100%; 15 | width: 100%; 16 | flex-grow: 1; 17 | 18 | /* PDFJS */ 19 | canvas{ 20 | margin: 0 auto; 21 | } 22 | .react-pdf__Document{ 23 | overflow-y: scroll; 24 | height: 100%; 25 | .react-pdf__Page{ 26 | margin-top: 15px; 27 | padding-bottom: 50px; 28 | } 29 | } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /config/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "general": { 3 | }, 4 | "features": { 5 | }, 6 | "log": { 7 | }, 8 | "email": { 9 | }, 10 | "oauth": { 11 | }, 12 | "connections": [ 13 | { 14 | "type": "webdav", 15 | "label": "WebDav" 16 | }, 17 | { 18 | "type": "ftp", 19 | "label": "FTP" 20 | }, 21 | { 22 | "type": "sftp", 23 | "label": "SFTP" 24 | }, 25 | { 26 | "type": "git", 27 | "label": "GIT" 28 | }, 29 | { 30 | "type": "s3", 31 | "label": "S3" 32 | }, 33 | { 34 | "type": "dropbox", 35 | "label": "Dropbox" 36 | }, 37 | { 38 | "type": "gdrive", 39 | "label": "Drive" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /embed.go: -------------------------------------------------------------------------------- 1 | package embed 2 | 3 | import ( 4 | "embed" 5 | "io/fs" 6 | "net/http" 7 | "os" 8 | ) 9 | 10 | var ( 11 | //go:embed public 12 | wwwPublic embed.FS 13 | WWWPublic http.FileSystem = http.FS(os.DirFS("./public/")) 14 | ) 15 | 16 | //go:embed server/plugin/index.go 17 | var EmbedPluginList []byte 18 | 19 | func init() { 20 | if os.Getenv("DEBUG") != "true" { 21 | fsPublic, _ := fs.Sub(wwwPublic, "public") 22 | WWWPublic = http.FS(fsPublic) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /public/Makefile: -------------------------------------------------------------------------------- 1 | compress: 2 | find . -type f -name '*.html' | xargs brotli -f -k 3 | find . -type f -name '*.html' | xargs gzip -f -k 4 | find . -type f -name '*.js' | xargs brotli -f -k 5 | find . -type f -name '*.js' | xargs gzip -f -k 6 | find . -type f -name '*.css' | xargs brotli -f -k 7 | find . -type f -name '*.css' | xargs gzip -f -k 8 | find . -type f -name '*.svg' | xargs brotli -f -k 9 | find . -type f -name '*.svg' | xargs gzip -f -k 10 | 11 | clean: 12 | find . -name '*.gz' -exec rm {} \; 13 | find . -name '*.br' -exec rm {} \; 14 | 15 | serve: 16 | go run server.go 17 | -------------------------------------------------------------------------------- /public/assets/boot/common.js: -------------------------------------------------------------------------------- 1 | export function $error(msg) { 2 | const $code = document.createElement("code"); 3 | $code.style.display = "block"; 4 | $code.style.margin = "20px 0"; 5 | $code.style.fontSize = "1.2rem"; 6 | $code.style.padding = "0 10% 0 10%"; 7 | $code.textContent = msg; 8 | 9 | const $img = document.createElement("img"); 10 | $img.setAttribute("src", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAABQAQMAAADcLOLWAAAABlBMVEUAAABTU1OoaSf/AAAAAXRSTlMAQObYZgAAAFlJREFUeF69zrERgCAQBdElMqQEOtHSuNIohRIMjfjO6DDmB7jZy5YgySQVYDIakIHD1kBPC9Bra5G2Ans0N7iAcOLF+EHvXySpjSBWCDI/3nIdBDihr8m4AcKdbn96jpAHAAAAAElFTkSuQmCC"); 11 | $img.style.display = "block"; 12 | $img.style.padding = "20vh 10% 0 10%"; 13 | 14 | document.body.innerHTML = ""; 15 | document.body.appendChild($img); 16 | document.body.appendChild($code); 17 | } 18 | -------------------------------------------------------------------------------- /public/assets/boot/ctrl_boot.d.ts: -------------------------------------------------------------------------------- 1 | export {}; 2 | 3 | interface IChromecast { 4 | init: () => Promise; 5 | } 6 | 7 | declare global { 8 | interface Window { 9 | env: string 10 | LNG: object; 11 | CONFIG: object; 12 | overrides: object; 13 | Chromecast: IChromecast; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /public/assets/boot/router_backoffice.js: -------------------------------------------------------------------------------- 1 | const routes = { 2 | "/admin/backend": "/pages/adminpage/ctrl_backend.js", 3 | "/admin/settings": "/pages/adminpage/ctrl_settings.js", 4 | "/admin/logs": "/pages/adminpage/ctrl_log.js", 5 | "/admin/about": "/pages/adminpage/ctrl_about.js", 6 | "/admin/setup": "/pages/adminpage/ctrl_setup.js", 7 | "/admin/": "/pages/ctrl_adminpage.js", 8 | "/admin": "/pages/ctrl_adminpage.js", 9 | "/logout": "/pages/ctrl_logout.js", 10 | "": "/pages/ctrl_notfound.js", 11 | }; 12 | 13 | export default routes; 14 | -------------------------------------------------------------------------------- /public/assets/boot/router_frontoffice.js: -------------------------------------------------------------------------------- 1 | const routes = { 2 | "/login": "/pages/ctrl_connectpage.js", 3 | "/logout": "/pages/ctrl_logout.js", 4 | 5 | "/": "/pages/ctrl_homepage.js", 6 | "/files/.*": "/pages/ctrl_filespage.js", 7 | "/view/.*": "/pages/ctrl_viewerpage.js", 8 | // /tags/.* -> "pages/ctrl_tags.js", 9 | "/s/.*": "/pages/ctrl_sharepage.js", 10 | 11 | "": "/pages/ctrl_notfound.js", 12 | }; 13 | 14 | export default routes; 15 | -------------------------------------------------------------------------------- /public/assets/components/dropdown.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/components/dropdown.css -------------------------------------------------------------------------------- /public/assets/components/fab.css: -------------------------------------------------------------------------------- 1 | .component_fab { 2 | position: fixed; 3 | bottom: 20px; 4 | right: 20px; 5 | z-index: 2; 6 | background: transparent; 7 | } 8 | .component_fab .content { 9 | height: 25px; 10 | width: 25px; 11 | padding: 13px; 12 | border-radius: 50%; 13 | background: var(--dark); 14 | box-shadow: rgba(0, 0, 0, 0.14) 0px 4px 5px 0px, rgba(0, 0, 0, 0.12) 0px 1px 10px 0px, rgba(0, 0, 0, 0.2) 0px 2px 4px -1px; 15 | z-index: 1000; 16 | cursor: pointer; 17 | } 18 | -------------------------------------------------------------------------------- /public/assets/components/fab.js: -------------------------------------------------------------------------------- 1 | import { loadCSS } from "../helpers/loader.js"; 2 | import assert from "../lib/assert.js"; 3 | 4 | export default class ComponentFab extends HTMLButtonElement { 5 | constructor() { 6 | super(); 7 | this.innerHTML = `
`; 8 | this.classList.add("component_fab"); 9 | } 10 | 11 | async render($icon) { 12 | await loadCSS(import.meta.url, "./fab.css"); 13 | assert.type(this.querySelector(".content"), HTMLElement).replaceChildren($icon); 14 | } 15 | } 16 | 17 | customElements.define("component-fab", ComponentFab, { extends: "button" }); 18 | -------------------------------------------------------------------------------- /public/assets/components/skeleton.js: -------------------------------------------------------------------------------- 1 | export function generateSkeleton(n) { 2 | const tmpl = "
"; 3 | let html = ""; 4 | for (let i = 0; i < n; i++) { 5 | html += tmpl; 6 | } 7 | return html; 8 | } 9 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_alert.css: -------------------------------------------------------------------------------- 1 | .alert { 2 | background: var(--bg-color); 3 | border-radius: 5px; 4 | padding: 20px; 5 | margin-top: 20px; 6 | margin-bottom: 20px; 7 | border: 1px solid rgba(0,0,0,0.05); 8 | } 9 | .alert ol, .alert ul { 10 | margin: 5px 0; 11 | padding: 0 20px; 12 | } 13 | .alert.success{ 14 | background: var(--success); 15 | } 16 | .alert.error{ 17 | background: var(--error); 18 | color: var(--bg-color); 19 | } 20 | .alert img{ 21 | max-width: 100%; 22 | border-radius: 5px; 23 | border: 10px solid white; 24 | box-sizing: border-box; 25 | margin-top: 5px; 26 | } 27 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_box.css: -------------------------------------------------------------------------------- 1 | .box{ 2 | padding: 10px; 3 | cursor: pointer; 4 | margin: 3px 0; 5 | overflow: hidden; 6 | position: relative; 7 | } 8 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_button.css: -------------------------------------------------------------------------------- 1 | button { 2 | border: none; 3 | margin: 0; 4 | padding: 6px; 5 | display: inline-block; 6 | outline: none; 7 | cursor: pointer; 8 | font-size: inherit; 9 | border-radius: 3px; 10 | color: rgba(0,0,0,0.6); 11 | background: inherit; 12 | } 13 | button.primary { 14 | background: var(--primary); 15 | color: white; 16 | } 17 | button.emphasis { 18 | background: var(--emphasis); 19 | color: white; 20 | } 21 | button.dark { 22 | background: var(--dark); 23 | color: white; 24 | } 25 | button.light { 26 | background: #e2e2e2; 27 | color: var(--dark); 28 | } 29 | button.large { 30 | width: 100%; 31 | } 32 | button[disabled] { 33 | opacity: 0.9; 34 | } 35 | 36 | .touch-no button.dark:hover, .touch-no button.emphasis:hover, .touch-no button.primary:hover { 37 | filter: brightness(95%); 38 | transition: 0.2s ease all; 39 | } 40 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_container.css: -------------------------------------------------------------------------------- 1 | .component_container{ 2 | width: 95%; 3 | max-width: 800px; 4 | margin: 0 auto; 5 | padding: 10px; 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_darkmode.css: -------------------------------------------------------------------------------- 1 | body.dark-mode { 2 | --bg-color: #1e1f22; 3 | --color: #f1f1f1; 4 | --light: #dfe1e5; 5 | 6 | 7 | --border: #303438; 8 | --dark: #2b2d30; 9 | } 10 | 11 | body.dark-mode input { 12 | color: var(--bg-color); 13 | } 14 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_icon.css: -------------------------------------------------------------------------------- 1 | .component_icon { 2 | vertical-align: bottom; 3 | max-height: 100%; 4 | } 5 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_skeleton.css: -------------------------------------------------------------------------------- 1 | .component_skeleton { 2 | width: 100%; 3 | height: 30px; 4 | background: linear-gradient(110deg, rgba(0,0,0,0.02) 8%, rgba(0,0,0,0.04) 18%, rgba(0,0,0,0.02) 33%); 5 | border-radius: 5px; 6 | background-size: 200% 100%; 7 | animation: 3s skeleton_shine linear infinite; 8 | margin-bottom: 15px; 9 | } 10 | 11 | @keyframes skeleton_shine { 12 | to { background-position-x: -200%; } 13 | } 14 | -------------------------------------------------------------------------------- /public/assets/css/designsystem_utils.css: -------------------------------------------------------------------------------- 1 | .pointer { 2 | cursor: pointer; 3 | } 4 | 5 | .hidden{ 6 | position:absolute!important; 7 | left:-10000px!important; 8 | top:auto!important; 9 | width:1px!important; 10 | height:1px!important; 11 | overflow:hidden!important; 12 | } 13 | 14 | .no-select { 15 | -webkit-touch-callout: none; 16 | -webkit-user-select: none; 17 | -khtml-user-select: none; 18 | -moz-user-select: none; 19 | -ms-user-select: none; 20 | user-select: none; 21 | -webkit-tap-highlight-color: transparent; 22 | } 23 | 24 | .center{ 25 | text-align: center; 26 | } 27 | 28 | .full-width { 29 | width: 100%; 30 | } 31 | 32 | .flex { 33 | display: flex; 34 | } 35 | 36 | .ellipsis { 37 | white-space: nowrap; 38 | overflow: hidden; 39 | text-overflow: ellipsis; 40 | } 41 | -------------------------------------------------------------------------------- /public/assets/fonts/SourceCodePro-Regular-400-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/fonts/SourceCodePro-Regular-400-latin-ext.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/SourceCodePro-Regular-400-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/fonts/SourceCodePro-Regular-400-latin.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/SourceCodePro-Semibold-600-latin-ext.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/fonts/SourceCodePro-Semibold-600-latin-ext.woff2 -------------------------------------------------------------------------------- /public/assets/fonts/SourceCodePro-Semibold-600-latin.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/fonts/SourceCodePro-Semibold-600-latin.woff2 -------------------------------------------------------------------------------- /public/assets/helpers/loader.d.ts: -------------------------------------------------------------------------------- 1 | export function loadScript(url: string): Promise; 2 | 3 | export function loadJS(baseURL: string, path: string, opts?: object): Promise; 4 | 5 | export function loadCSS(baseURL: string, ...arrayOfFilenames: string[]): Promise; 6 | 7 | export function loadCSSInline(baseURL: string, filename: string): Promise; 8 | 9 | export function CSS(baseURL: string, ...arrayOfFilenames: string[]): Promise; 10 | 11 | export function init(): Promise; -------------------------------------------------------------------------------- /public/assets/helpers/log.d.ts: -------------------------------------------------------------------------------- 1 | export function report(msg: Event|string, err?: any, link?: string, lineNo?: number, columnno?: number); -------------------------------------------------------------------------------- /public/assets/helpers/log.js: -------------------------------------------------------------------------------- 1 | import { toHref } from "../lib/skeleton/router.js"; 2 | import ajax from "../lib/ajax.js"; 3 | 4 | export function report(msg, err, link, lineNo, columnNo) { 5 | if (window.navigator.onLine === false) return Promise.resolve(); 6 | let url = toHref("/report?"); 7 | url += "url=" + encodeURIComponent(location.href) + "&"; 8 | url += "msg=" + encodeURIComponent(msg) + "&"; 9 | url += "from=" + encodeURIComponent(link) + "&"; 10 | url += "from.lineNo=" + lineNo + "&"; 11 | url += "from.columnNo=" + columnNo; 12 | if (err instanceof Error) url += "error=" + encodeURIComponent(err.message) + "&"; 13 | 14 | return ajax({ url, method: "post" }).toPromise().catch(() => {}); 15 | } 16 | -------------------------------------------------------------------------------- /public/assets/helpers/sdk.js: -------------------------------------------------------------------------------- 1 | // feature detection if we're using Filestash as a standalone app or as an SDK 2 | // see: ../index.js 3 | 4 | export function isSDK() { 5 | const importURL = new URL(import.meta.url); 6 | return location.origin !== importURL.origin; 7 | } 8 | 9 | export function urlSDK(url) { 10 | if (url.startsWith("blob:")) return url; 11 | else if (url.startsWith("http://") || url.startsWith("https://")) return url; 12 | 13 | const importURL = new URL(import.meta.url); 14 | if (new RegExp("^/").test(url) === false) { 15 | url = "/" + url; 16 | } 17 | return importURL.origin + url; 18 | } 19 | -------------------------------------------------------------------------------- /public/assets/lib/dom.d.ts: -------------------------------------------------------------------------------- 1 | export function qs($node: HTMLElement | DocumentFragment, selector: string); 2 | 3 | export function qsa($node: HTMLElement | DocumentFragment, selector: string); 4 | 5 | export function safe(str: string): string; 6 | -------------------------------------------------------------------------------- /public/assets/lib/dom.js: -------------------------------------------------------------------------------- 1 | export function qs($node, selector) { 2 | if (!$node) throw new TypeError("undefined node"); 3 | const $target = $node.querySelector(selector); 4 | if (!$target) throw new DOMException(`undefined node for selector '${selector}'`, "NotFoundError"); 5 | return $target; 6 | } 7 | 8 | export function qsa($node, selector) { 9 | if (!$node) throw new TypeError("undefined node"); 10 | return $node.querySelectorAll(selector); 11 | } 12 | 13 | export function safe(str) { 14 | if (typeof str !== "string") return ""; 15 | 16 | const $div = document.createElement("div"); 17 | $div.textContent = str; 18 | return ($div.innerHTML || "") 19 | 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/lib/error.d.ts: -------------------------------------------------------------------------------- 1 | export class AjaxError extends Error { 2 | constructor(message: string, err?: any, code?: string); 3 | code(): string; 4 | err(): any; 5 | type(): string; 6 | } 7 | 8 | export class ApplicationError extends Error { 9 | constructor(message: string, debug: string); 10 | debugMsg: string; 11 | type(): string; 12 | debug(): string; 13 | } 14 | -------------------------------------------------------------------------------- /public/assets/lib/error.js: -------------------------------------------------------------------------------- 1 | export class AjaxError extends Error { 2 | constructor(message, err = null, code = "UNDEFINED_CODE") { 3 | super(message); 4 | this.name = this.constructor.name; 5 | this.errCode = code; 6 | this.errOrig = err; 7 | } 8 | 9 | code() { 10 | return this.errCode; 11 | } 12 | 13 | err() { 14 | return this.errOrig; 15 | } 16 | 17 | type() { 18 | return "AjaxError"; 19 | } 20 | } 21 | 22 | export class ApplicationError extends Error { 23 | constructor(message, debug) { 24 | super(message); 25 | this.debugMsg = debug; 26 | } 27 | 28 | type() { 29 | return "ApplicationError"; 30 | } 31 | 32 | debug() { 33 | return this.debugMsg || "N/A"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /public/assets/lib/form.d.ts: -------------------------------------------------------------------------------- 1 | // type FormOption = { 2 | // }; 3 | 4 | export function mutateForm(formSpec: object, formState: object): object; 5 | 6 | export function createFormNodes(node: object, opts: object): Promise; 7 | 8 | export function createForm(node: object, opts: object): Promise; 9 | -------------------------------------------------------------------------------- /public/assets/lib/path.js: -------------------------------------------------------------------------------- 1 | export function basename(str, sep = "/") { 2 | return str.substr(str.lastIndexOf(sep) + 1); 3 | } 4 | 5 | export function extname(str) { 6 | return str.substr(str.lastIndexOf(".") + 1).toLowerCase(); 7 | } 8 | 9 | export function join(baseURL, segment) { 10 | const url = new URL(segment, baseURL); 11 | return decodeURIComponent(url.pathname + url.hash); 12 | } 13 | 14 | export function forwardURLParams(url, allowed = []) { 15 | const _url = new URL(window.location.origin + "/" + url); 16 | for (const [key, value] of new URLSearchParams(location.search)) { 17 | if (allowed.indexOf(key) < 0) continue; 18 | _url.searchParams.set(key, value); 19 | } 20 | return _url.pathname.substring(1) + _url.search; 21 | } 22 | -------------------------------------------------------------------------------- /public/assets/lib/polyfill.js: -------------------------------------------------------------------------------- 1 | Document.prototype.replaceChildren = replaceChildren; 2 | DocumentFragment.prototype.replaceChildren = replaceChildren; 3 | Element.prototype.replaceChildren = replaceChildren; 4 | 5 | function replaceChildren(...new_children) { 6 | const { childNodes } = this; 7 | while (childNodes.length) { 8 | childNodes[0].remove(); 9 | } 10 | this.append(...new_children); 11 | } 12 | -------------------------------------------------------------------------------- /public/assets/lib/random.d.ts: -------------------------------------------------------------------------------- 1 | export function gid(prefix: string): string; 2 | 3 | export function randomString(size: number): string; 4 | -------------------------------------------------------------------------------- /public/assets/lib/random.js: -------------------------------------------------------------------------------- 1 | export function gid(prefix = "") { 2 | let id = prefix; 3 | id += new Date().getTime().toString(32); 4 | id += Math.random().toString(32).replace(/^0\./, ""); 5 | return id; 6 | } 7 | 8 | const alphabet = [ 9 | "a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", 10 | "q", "r", "s", "t", "u", "v", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", 11 | "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", 12 | "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", 13 | ]; 14 | const alphabet_size = alphabet.length; 15 | 16 | export function randomString(size = 16) { 17 | let str = ""; 18 | for (let i=0; i { 13 | window.localStorage.setItem("settings", JSON.stringify(settings)); 14 | }, 0); 15 | } 16 | -------------------------------------------------------------------------------- /public/assets/lib/skeleton/index.d.ts: -------------------------------------------------------------------------------- 1 | import { onDestroy } from "./lifecycle"; 2 | import { navigate } from "./router"; 3 | 4 | export default function($root: HTMLElement | null, routes: object, opts: object); 5 | 6 | export function createElement(str: string): HTMLElement; 7 | 8 | export function createFragment(str: string): DocumentFragment; 9 | 10 | export function createRender($parent: HTMLElement | null): (HTMLElement) => void; 11 | 12 | export function nop(): void 13 | 14 | export { onDestroy, navigate }; 15 | -------------------------------------------------------------------------------- /public/assets/lib/skeleton/lifecycle.d.ts: -------------------------------------------------------------------------------- 1 | export function init($root: HTMLElement): Promise; 2 | 3 | export function onDestroy(fn: Function): Promise; -------------------------------------------------------------------------------- /public/assets/lib/skeleton/lifecycle.js: -------------------------------------------------------------------------------- 1 | let _cleanup = []; 2 | 3 | export async function init($root) { 4 | $root.cleanup = () => { 5 | const fns = _cleanup.map((fn) => fn($root)); 6 | _cleanup = []; 7 | return Promise.all(fns); 8 | }; 9 | } 10 | 11 | export async function onDestroy(fn) { 12 | _cleanup.push(fn); 13 | } 14 | -------------------------------------------------------------------------------- /public/assets/lib/skeleton/router.d.ts: -------------------------------------------------------------------------------- 1 | export function init($root: HTMLElement): Promise; 2 | 3 | export function navigate(href: string); 4 | 5 | export function currentRoute(r: object, notFoundRoute: string); 6 | 7 | export function base(); 8 | 9 | export function fromHref(h: string): string; 10 | 11 | export function toHref(h: string): string; -------------------------------------------------------------------------------- /public/assets/lib/store.js: -------------------------------------------------------------------------------- 1 | export function settingsGet(initialValues, prefix = "") { 2 | const raw = JSON.parse(localStorage.getItem("settings") || "{}") || {}; 3 | const currentSettings = {}; 4 | Object.keys(initialValues).forEach((key) => { 5 | const settingsKey = prefix ? `${prefix}_${key}` : key; 6 | if (settingsKey in raw) currentSettings[key] = raw[settingsKey]; 7 | else currentSettings[key] = initialValues[key]; 8 | }); 9 | return currentSettings; 10 | } 11 | 12 | export function settingsSave(currentValues, prefix = "") { 13 | const raw = JSON.parse(localStorage.getItem("settings") || "{}") || {}; 14 | Object.keys(currentValues).forEach((key) => { 15 | const settingsKey = prefix ? `${prefix}_${key}` : key; 16 | raw[settingsKey] = currentValues[key]; 17 | }); 18 | localStorage.setItem("settings", JSON.stringify(raw)); 19 | } 20 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/.gitattributes: -------------------------------------------------------------------------------- 1 | *.txt text eol=lf 2 | *.js text eol=lf 3 | *.html text eol=lf 4 | *.md text eol=lf 5 | *.json text eol=lf 6 | *.yml text eol=lf 7 | *.css text eol=lf 8 | *.svg text eol=lf 9 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/.npmignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /demo 3 | /doc 4 | /test 5 | /test*.html 6 | /index.html 7 | /mode/*/*test.js 8 | /mode/*/*.html 9 | /mode/index.html 10 | .* 11 | /bin/authors.sh 12 | /bin/lint 13 | /bin/release 14 | /bin/upload-release.js 15 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/addon/dialog/dialog.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-dialog { 2 | position: absolute; 3 | left: 0; right: 0; 4 | background: inherit; 5 | z-index: 15; 6 | padding: .1em .8em; 7 | overflow: hidden; 8 | color: inherit; 9 | } 10 | 11 | .CodeMirror-dialog-top { 12 | border-bottom: 1px solid #eee; 13 | top: 0; 14 | } 15 | 16 | .CodeMirror-dialog-bottom { 17 | border-top: 1px solid #eee; 18 | bottom: 0; 19 | } 20 | 21 | .CodeMirror-dialog input { 22 | border: none; 23 | outline: none; 24 | background: transparent; 25 | width: 20em; 26 | color: inherit; 27 | font-family: monospace; 28 | } 29 | 30 | .CodeMirror-dialog button { 31 | font-size: 70%; 32 | } 33 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/addon/display/fullscreen.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-fullscreen { 2 | position: fixed; 3 | top: 0; left: 0; right: 0; bottom: 0; 4 | height: auto; 5 | z-index: 9; 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/addon/fold/foldgutter.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-foldmarker { 2 | color: blue; 3 | text-shadow: #b9f 1px 1px 2px, #b9f -1px -1px 2px, #b9f 1px -1px 2px, #b9f -1px 1px 2px; 4 | font-family: arial; 5 | line-height: .3; 6 | cursor: pointer; 7 | } 8 | .CodeMirror-foldgutter { 9 | width: .7em; 10 | } 11 | .CodeMirror-foldgutter-open, 12 | .CodeMirror-foldgutter-folded { 13 | cursor: pointer; 14 | } 15 | .CodeMirror-foldgutter-open:after { 16 | content: "\25BE"; 17 | } 18 | .CodeMirror-foldgutter-folded:after { 19 | content: "\25B8"; 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/addon/hint/show-hint.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-hints { 2 | position: absolute; 3 | z-index: 10; 4 | overflow: hidden; 5 | list-style: none; 6 | 7 | margin: 0; 8 | padding: 2px; 9 | 10 | -webkit-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 11 | -moz-box-shadow: 2px 3px 5px rgba(0,0,0,.2); 12 | box-shadow: 2px 3px 5px rgba(0,0,0,.2); 13 | border-radius: 3px; 14 | border: 1px solid silver; 15 | 16 | background: white; 17 | font-size: 90%; 18 | font-family: monospace; 19 | 20 | max-height: 20em; 21 | overflow-y: auto; 22 | box-sizing: border-box; 23 | } 24 | 25 | .CodeMirror-hint { 26 | margin: 0; 27 | padding: 0 4px; 28 | border-radius: 2px; 29 | white-space: pre; 30 | color: black; 31 | cursor: pointer; 32 | } 33 | 34 | li.CodeMirror-hint-active { 35 | background: #08f; 36 | color: white; 37 | } 38 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/addon/search/matchesonscrollbar.css: -------------------------------------------------------------------------------- 1 | .CodeMirror-search-match { 2 | background: gold; 3 | border-top: 1px solid orange; 4 | border-bottom: 1px solid orange; 5 | -moz-box-sizing: border-box; 6 | box-sizing: border-box; 7 | opacity: .5; 8 | } 9 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/bin/authors.sh: -------------------------------------------------------------------------------- 1 | # Combine existing list of authors with everyone known in git, sort, add header. 2 | tail --lines=+3 AUTHORS > AUTHORS.tmp 3 | git log --format='%aN' | grep -v "Piët Delport" >> AUTHORS.tmp 4 | echo -e "List of CodeMirror contributors. Updated before every release.\n" > AUTHORS 5 | sort -u AUTHORS.tmp | sed 's/Google Inc\./Google LLC/' >> AUTHORS 6 | rm -f AUTHORS.tmp 7 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/bin/lint: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | process.exit(require("../test/lint").ok ? 0 : 1); 4 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/doc/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/codemirror/doc/logo.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/doc/source_sans.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/codemirror/doc/source_sans.woff -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/doc/yinyang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/codemirror/doc/yinyang.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/mode/css/gss_test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function() { 5 | "use strict"; 6 | 7 | var mode = CodeMirror.getMode({indentUnit: 2}, "text/x-gss"); 8 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1), "gss"); } 9 | 10 | MT("atComponent", 11 | "[def @component] {", 12 | "[tag foo] {", 13 | " [property color]: [keyword black];", 14 | "}", 15 | "}"); 16 | 17 | })(); 18 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/mode/d/test.js: -------------------------------------------------------------------------------- 1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others 2 | // Distributed under an MIT license: https://codemirror.net/5/LICENSE 3 | 4 | (function() { 5 | var mode = CodeMirror.getMode({indentUnit: 2}, "d"); 6 | function MT(name) { test.mode(name, mode, Array.prototype.slice.call(arguments, 1)); } 7 | 8 | MT("nested_comments", 9 | "[comment /+]","[comment comment]","[comment +/]","[variable void] [variable main](){}"); 10 | 11 | })(); 12 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/mode/tiddlywiki/tiddlywiki.css: -------------------------------------------------------------------------------- 1 | span.cm-underlined { 2 | text-decoration: underline; 3 | } 4 | span.cm-strikethrough { 5 | text-decoration: line-through; 6 | } 7 | span.cm-brace { 8 | color: #170; 9 | font-weight: bold; 10 | } 11 | span.cm-table { 12 | color: blue; 13 | font-weight: bold; 14 | } 15 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/mode/tiki/tiki.css: -------------------------------------------------------------------------------- 1 | .cm-tw-syntaxerror { 2 | color: #FFF; 3 | background-color: #900; 4 | } 5 | 6 | .cm-tw-deleted { 7 | text-decoration: line-through; 8 | } 9 | 10 | .cm-tw-header5 { 11 | font-weight: bold; 12 | } 13 | .cm-tw-listitem:first-child { /*Added first child to fix duplicate padding when highlighting*/ 14 | padding-left: 10px; 15 | } 16 | 17 | .cm-tw-box { 18 | border-top-width: 0px !important; 19 | border-style: solid; 20 | border-width: 1px; 21 | border-color: inherit; 22 | } 23 | 24 | .cm-tw-underline { 25 | text-decoration: underline; 26 | } -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/addon/runmode/runmode-standalone.js: -------------------------------------------------------------------------------- 1 | import "./codemirror-standalone.js" 2 | import "../../../addon/runmode/runmode.js" -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/addon/runmode/runmode.node.js: -------------------------------------------------------------------------------- 1 | import "./codemirror.node.js" 2 | import "../../../addon/runmode/runmode.js" -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/codemirror.js: -------------------------------------------------------------------------------- 1 | import { CodeMirror } from "./edit/main.js" 2 | 3 | export default CodeMirror 4 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/display/mode_state.js: -------------------------------------------------------------------------------- 1 | import { getMode } from "../modes.js" 2 | 3 | import { startWorker } from "./highlight_worker.js" 4 | import { regChange } from "./view_tracking.js" 5 | 6 | // Used to get the editor into a consistent state again when options change. 7 | 8 | export function loadMode(cm) { 9 | cm.doc.mode = getMode(cm.options, cm.doc.modeOption) 10 | resetModeState(cm) 11 | } 12 | 13 | export function resetModeState(cm) { 14 | cm.doc.iter(line => { 15 | if (line.stateAfter) line.stateAfter = null 16 | if (line.styles) line.styles = null 17 | }) 18 | cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first 19 | startWorker(cm, 100) 20 | cm.state.modeGen++ 21 | if (cm.curOp) regChange(cm) 22 | } 23 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/edit/utils.js: -------------------------------------------------------------------------------- 1 | import { clearCaches } from "../measurement/position_measurement.js" 2 | 3 | export function themeChanged(cm) { 4 | cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") + 5 | cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-") 6 | clearCaches(cm) 7 | } 8 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/src/line/saw_special_spans.js: -------------------------------------------------------------------------------- 1 | // Optimize some code when these features are not used. 2 | export let sawReadOnlySpans = false, sawCollapsedSpans = false 3 | 4 | export function seeReadOnlySpans() { 5 | sawReadOnlySpans = true 6 | } 7 | 8 | export function seeCollapsedSpans() { 9 | sawCollapsedSpans = true 10 | } 11 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/theme/ambiance-mobile.css: -------------------------------------------------------------------------------- 1 | .cm-s-ambiance.CodeMirror { 2 | -webkit-box-shadow: none; 3 | -moz-box-shadow: none; 4 | box-shadow: none; 5 | } 6 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/theme/elegant.css: -------------------------------------------------------------------------------- 1 | .cm-s-elegant span.cm-number, .cm-s-elegant span.cm-string, .cm-s-elegant span.cm-atom { color: #762; } 2 | .cm-s-elegant span.cm-comment { color: #262; font-style: italic; line-height: 1em; } 3 | .cm-s-elegant span.cm-meta { color: #555; font-style: italic; line-height: 1em; } 4 | .cm-s-elegant span.cm-variable { color: black; } 5 | .cm-s-elegant span.cm-variable-2 { color: #b11; } 6 | .cm-s-elegant span.cm-qualifier { color: #555; } 7 | .cm-s-elegant span.cm-keyword { color: #730; } 8 | .cm-s-elegant span.cm-builtin { color: #30a; } 9 | .cm-s-elegant span.cm-link { color: #762; } 10 | .cm-s-elegant span.cm-error { background-color: #fdd; } 11 | 12 | .cm-s-elegant .CodeMirror-activeline-background { background: #e8f2ff; } 13 | .cm-s-elegant .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } 14 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/theme/juejin.css: -------------------------------------------------------------------------------- 1 | .cm-s-juejin.CodeMirror { 2 | background: #f8f9fa; 3 | } 4 | .cm-s-juejin .cm-header, 5 | .cm-s-juejin .cm-def { 6 | color: #1ba2f0; 7 | } 8 | .cm-s-juejin .cm-comment { 9 | color: #009e9d; 10 | } 11 | .cm-s-juejin .cm-quote, 12 | .cm-s-juejin .cm-link, 13 | .cm-s-juejin .cm-strong, 14 | .cm-s-juejin .cm-attribute { 15 | color: #fd7741; 16 | } 17 | .cm-s-juejin .cm-url, 18 | .cm-s-juejin .cm-keyword, 19 | .cm-s-juejin .cm-builtin { 20 | color: #bb51b8; 21 | } 22 | .cm-s-juejin .cm-hr { 23 | color: #909090; 24 | } 25 | .cm-s-juejin .cm-tag { 26 | color: #107000; 27 | } 28 | .cm-s-juejin .cm-variable-2 { 29 | color: #0050a0; 30 | } 31 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/theme/neat.css: -------------------------------------------------------------------------------- 1 | .cm-s-neat span.cm-comment { color: #a86; } 2 | .cm-s-neat span.cm-keyword { line-height: 1em; font-weight: bold; color: blue; } 3 | .cm-s-neat span.cm-string { color: #a22; } 4 | .cm-s-neat span.cm-builtin { line-height: 1em; font-weight: bold; color: #077; } 5 | .cm-s-neat span.cm-special { line-height: 1em; font-weight: bold; color: #0aa; } 6 | .cm-s-neat span.cm-variable { color: black; } 7 | .cm-s-neat span.cm-number, .cm-s-neat span.cm-atom { color: #3a3; } 8 | .cm-s-neat span.cm-meta { color: #555; } 9 | .cm-s-neat span.cm-link { color: #3a3; } 10 | 11 | .cm-s-neat .CodeMirror-activeline-background { background: #e8f2ff; } 12 | .cm-s-neat .CodeMirror-matchingbracket { outline:1px solid grey; color:black !important; } 13 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/codemirror/theme/ssms.css: -------------------------------------------------------------------------------- 1 | .cm-s-ssms span.cm-keyword { color: blue; } 2 | .cm-s-ssms span.cm-comment { color: darkgreen; } 3 | .cm-s-ssms span.cm-string { color: red; } 4 | .cm-s-ssms span.cm-def { color: black; } 5 | .cm-s-ssms span.cm-variable { color: black; } 6 | .cm-s-ssms span.cm-variable-2 { color: black; } 7 | .cm-s-ssms span.cm-atom { color: darkgray; } 8 | .cm-s-ssms .CodeMirror-linenumber { color: teal; } 9 | .cm-s-ssms .CodeMirror-activeline-background { background: #ffffff; } 10 | .cm-s-ssms span.cm-string-2 { color: #FF00FF; } 11 | .cm-s-ssms span.cm-operator, 12 | .cm-s-ssms span.cm-bracket, 13 | .cm-s-ssms span.cm-punctuation { color: darkgray; } 14 | .cm-s-ssms .CodeMirror-gutters { border-right: 3px solid #ffee62; background-color: #ffffff; } 15 | .cm-s-ssms div.CodeMirror-selected { background: #ADD6FF; } 16 | 17 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/assets/rulers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/leaflet/assets/rulers.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/ext/LatLngUtil.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class L.LatLngUtil 3 | * @aka LatLngUtil 4 | */ 5 | L.LatLngUtil = { 6 | // Clones a LatLngs[], returns [][] 7 | 8 | // @method cloneLatLngs(LatLngs[]): L.LatLngs[] 9 | // Clone the latLng point or points or nested points and return an array with those points 10 | cloneLatLngs: function (latlngs) { 11 | var clone = []; 12 | for (var i = 0, l = latlngs.length; i < l; i++) { 13 | // Check for nested array (Polyline/Polygon) 14 | if (Array.isArray(latlngs[i])) { 15 | clone.push(L.LatLngUtil.cloneLatLngs(latlngs[i])); 16 | } else { 17 | clone.push(this.cloneLatLng(latlngs[i])); 18 | } 19 | } 20 | return clone; 21 | }, 22 | 23 | // @method cloneLatLng(LatLng): L.LatLng 24 | // Clone the latLng and return a new LatLng object. 25 | cloneLatLng: function (latlng) { 26 | return L.latLng(latlng.lat, latlng.lng); 27 | } 28 | }; 29 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/ext/LineUtil.Intersect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @class L.LineUtil 3 | * @aka Util 4 | * @aka L.Utils 5 | */ 6 | L.Util.extend(L.LineUtil, { 7 | 8 | // @method segmentsIntersect(): boolean 9 | // Checks to see if two line segments intersect. Does not handle degenerate cases. 10 | // http://compgeom.cs.uiuc.edu/~jeffe/teaching/373/notes/x06-sweepline.pdf 11 | segmentsIntersect: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2, /*Point*/ p3) { 12 | return this._checkCounterclockwise(p, p2, p3) !== 13 | this._checkCounterclockwise(p1, p2, p3) && 14 | this._checkCounterclockwise(p, p1, p2) !== 15 | this._checkCounterclockwise(p, p1, p3); 16 | }, 17 | 18 | // check to see if points are in counterclockwise order 19 | _checkCounterclockwise: function (/*Point*/ p, /*Point*/ p1, /*Point*/ p2) { 20 | return (p2.y - p.y) * (p1.x - p.x) > (p1.y - p.y) * (p2.x - p.x); 21 | } 22 | }); 23 | -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/images/layers.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/leaflet/images/layers.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/images/marker-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/leaflet/images/marker-icon.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/leaflet/images/marker-shadow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/lib/vendor/leaflet/images/marker-shadow.png -------------------------------------------------------------------------------- /public/assets/lib/vendor/rxjs/rxjs-ajax.min.js: -------------------------------------------------------------------------------- 1 | /* rxjs@7.8.1 */ 2 | export{ca as AjaxError,cc as AjaxResponse,cb as AjaxTimeoutError,c9 as ajax}from"./rxjs-shared.min.js"; 3 | -------------------------------------------------------------------------------- /public/assets/logo/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/assets/logo/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/assets/logo/app_icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/app_icon.png -------------------------------------------------------------------------------- /public/assets/logo/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/apple-touch-icon.png -------------------------------------------------------------------------------- /public/assets/logo/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/favicon-16x16.png -------------------------------------------------------------------------------- /public/assets/logo/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/favicon-32x32.png -------------------------------------------------------------------------------- /public/assets/logo/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/favicon.ico -------------------------------------------------------------------------------- /public/assets/logo/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/mstile-150x150.png -------------------------------------------------------------------------------- /public/assets/logo/og-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mickael-kerjean/filestash/f1048299f6c56671ddd3568c986439c80e6a6037/public/assets/logo/og-image.png -------------------------------------------------------------------------------- /public/assets/model/backend.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../lib/rx.js"; 2 | import ajax from "../lib/ajax.js"; 3 | 4 | const backend$ = ajax({ 5 | url: "api/backend", 6 | method: "GET", 7 | responseType: "json" 8 | }).pipe( 9 | rxjs.map(({ responseJSON }) => responseJSON.result), 10 | ); 11 | 12 | export function getBackends() { 13 | return backend$; 14 | } 15 | -------------------------------------------------------------------------------- /public/assets/model/config.d.ts: -------------------------------------------------------------------------------- 1 | interface Config { 2 | [key: string]: any; 3 | thumbnailer: string[]; 4 | } 5 | 6 | export function init(): Promise; 7 | 8 | export function get(): Config; 9 | 10 | export function get(key: string, defaultValue?: T): T; 11 | 12 | export function getVersion(): string; 13 | 14 | export function query(): any; -------------------------------------------------------------------------------- /public/assets/model/config.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../lib/rx.js"; 2 | import ajax from "../lib/ajax.js"; 3 | 4 | const config$ = ajax({ 5 | url: "api/config", 6 | method: "GET", 7 | responseType: "json", 8 | }).pipe( 9 | rxjs.map(({ responseJSON }) => responseJSON.result), 10 | ); 11 | 12 | let CONFIG = {}; 13 | 14 | export async function init() { 15 | const config = await config$.toPromise(); 16 | CONFIG = config; 17 | return config; 18 | } 19 | 20 | export function get(key, defaultValue) { 21 | if (key) return CONFIG[key] || defaultValue; 22 | return CONFIG; 23 | } 24 | 25 | export function getVersion() { 26 | return get("version", "na"); 27 | } 28 | 29 | export function query() { 30 | return config$; 31 | } 32 | -------------------------------------------------------------------------------- /public/assets/model/plugin.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../lib/rx.js"; 2 | import ajax from "../lib/ajax.js"; 3 | 4 | const plugin$ = ajax({ 5 | url: "api/plugin", 6 | method: "GET", 7 | responseType: "json", 8 | }).pipe( 9 | rxjs.map(({ responseJSON }) => responseJSON.result), 10 | ); 11 | 12 | let plugins = {}; 13 | 14 | export async function init() { 15 | plugins = await plugin$.toPromise(); 16 | } 17 | 18 | export function get(mime) { 19 | return plugins[mime]; 20 | } 21 | 22 | export async function load(mime) { 23 | const specs = plugins[mime]; 24 | if (!specs) return null; 25 | const [, url] = specs; 26 | const module = await import(url); 27 | return module.default; 28 | } 29 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/animate.js: -------------------------------------------------------------------------------- 1 | import { transition, slideYIn } from "../../lib/animate.js"; 2 | 3 | export default function($node) { 4 | return transition($node, { 5 | timeEnter: 100, 6 | enter: slideYIn(3) 7 | }); 8 | } 9 | 10 | export const cssHideMenu = ".component_menu_sidebar{transform: translateX(-300px)}"; 11 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/ctrl_about.css: -------------------------------------------------------------------------------- 1 | .component_page_about { 2 | padding-top: 50px; 3 | overflow-x: auto; 4 | } 5 | .component_page_about .small { 6 | font-size: 0.9rem; 7 | padding: 0px 2px; 8 | } 9 | .component_page_about a { 10 | padding: 0 2px; 11 | } 12 | .component_page_about a:hover { 13 | background: rgba(0, 0, 0, 0.05); 14 | border-top-left-radius: 5px; 15 | border-top-right-radius: 5px; 16 | } 17 | .component_page_about table { 18 | border-spacing: 0px 20px; 19 | } 20 | .component_page_about td { 21 | vertical-align: top; 22 | } 23 | .component_page_about td br { 24 | content: ""; 25 | margin: 15px; 26 | display: block; 27 | } 28 | .component_page_about td:first-of-type { 29 | font-weight: bold; 30 | } 31 | .component_page_about td:first-of-type:after { 32 | content: ": "; 33 | } 34 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/ctrl_about.js: -------------------------------------------------------------------------------- 1 | import { createElement } from "../../lib/skeleton/index.js"; 2 | import rxjs, { effect, stateMutation } from "../../lib/rx.js"; 3 | import { qs } from "../../lib/dom.js"; 4 | import { CSS } from "../../helpers/loader.js"; 5 | 6 | import AdminHOC from "./decorator.js"; 7 | import { get as getRelease } from "./model_release.js"; 8 | import transition from "./animate.js"; 9 | 10 | export default AdminHOC(async function(render) { 11 | const $page = createElement(` 12 |
13 | 14 |
15 |
16 | `); 17 | render(transition($page)); 18 | 19 | effect(getRelease().pipe( 20 | rxjs.map(({ html }) => html), 21 | stateMutation(qs($page, "[data-bind=\"about\"]"), "innerHTML"), 22 | )); 23 | }); 24 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/ctrl_log_viewer.css: -------------------------------------------------------------------------------- 1 | .component_logpage button{ 2 | width: inherit; 3 | float: right; 4 | margin-top: 5px; 5 | padding-left: 20px; 6 | padding-right: 20px; 7 | } 8 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/ctrl_login.css: -------------------------------------------------------------------------------- 1 | .component_page_adminlogin { 2 | max-width: 300px; 3 | } 4 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/decorator.js: -------------------------------------------------------------------------------- 1 | import { createElement } from "../../lib/skeleton/index.js"; 2 | import AdminOnly from "./decorator_admin_only.js"; 3 | import WithShell from "./decorator_sidemenu.js"; 4 | 5 | import "../../components/loader.js"; 6 | 7 | export default function HOC(ctrlPage) { 8 | const ctrlLoading = (render) => { 9 | render(createElement("")); 10 | }; 11 | 12 | return (render) => { 13 | AdminOnly(WithShell(ctrlPage))(render); 14 | 15 | return (render) => { 16 | WithShell(ctrlLoading)(render); 17 | }; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/decorator_admin_only.js: -------------------------------------------------------------------------------- 1 | import rxjs, { effect } from "../../lib/rx.js"; 2 | import ctrlError from "../ctrl_error.js"; 3 | 4 | import ctrlLogin from "./ctrl_login.js"; 5 | import { isAdmin$ } from "./model_admin_session.js"; 6 | 7 | export default function AdminOnly(ctrlWrapped) { 8 | return (render) => { 9 | effect(isAdmin$().pipe( 10 | rxjs.map((isAdmin) => isAdmin ? ctrlWrapped : ctrlLogin), 11 | rxjs.tap((ctrl) => ctrl(render)), 12 | rxjs.catchError(ctrlError(render)), 13 | )); 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/model_audit.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | const isLoading$ = new rxjs.BehaviorSubject(false); 5 | 6 | export function get(searchParams = new URLSearchParams()) { 7 | return ajax({ 8 | url: "admin/api/audit?" + searchParams.toString(), 9 | responseType: "json" 10 | }).pipe( 11 | rxjs.map(({ responseJSON }) => responseJSON.result) 12 | ); 13 | } 14 | 15 | export function setLoader(value) { 16 | return isLoading$.next(!!value); 17 | } 18 | 19 | export function isLoading() { 20 | return isLoading$.asObservable(); 21 | } 22 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/model_auth_middleware.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | const model$ = ajax({ 5 | url: "admin/api/middlewares/authentication", 6 | method: "GET", 7 | responseType: "json" 8 | }).pipe( 9 | rxjs.map(({ responseJSON }) => responseJSON.result), 10 | rxjs.share(), 11 | ); 12 | 13 | export function getAuthMiddleware() { 14 | return model$; 15 | } 16 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/model_backend.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | 3 | import { getBackends as _getBackends } from "../../model/backend.js"; 4 | import { isSaving } from "./model_config.js"; 5 | 6 | const backend$ = _getBackends().pipe(rxjs.shareReplay(1)); 7 | 8 | export function getBackends() { 9 | return isSaving().pipe( 10 | rxjs.filter((loading) => !loading), 11 | rxjs.mergeMap(() => backend$), 12 | ); 13 | } 14 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/model_log.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | const log$ = ajax({ 5 | url: url(1024 * 100), // fetch the last 100kb by default 6 | responseType: "text", 7 | }).pipe( 8 | rxjs.map(({ response }) => response), 9 | ); 10 | 11 | export function url(logSize = 0) { 12 | return "admin/api/logs" + (logSize ? `?maxSize=${logSize}` : ""); 13 | } 14 | 15 | export function get() { 16 | return log$.pipe( 17 | rxjs.repeat({ delay: 10000 }), 18 | ); 19 | } 20 | -------------------------------------------------------------------------------- /public/assets/pages/adminpage/model_release.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | const release$ = ajax({ 5 | url: "about", 6 | responseType: "text", 7 | }).pipe(rxjs.shareReplay(1)); 8 | 9 | export function get() { 10 | return release$.pipe( 11 | rxjs.map(({ response, responseHeaders }) => { 12 | const a = document.createElement("html"); 13 | a.innerHTML = response; 14 | return { 15 | html: a.querySelector("table")?.outerHTML, 16 | version: responseHeaders["x-powered-by"].trim().replace(/^Filestash\/([v\.0-9]*).*$/, "$1") 17 | }; 18 | }), 19 | ); 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/pages/connectpage/ctrl_form_state.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | 3 | const currentBackend$ = new rxjs.ReplaySubject(1); 4 | 5 | export function setCurrentBackend(n) { 6 | currentBackend$.next(n); 7 | } 8 | 9 | export function getCurrentBackend() { 10 | return currentBackend$.asObservable(); 11 | } 12 | 13 | export function getURLParams() { 14 | return [...new URLSearchParams(location.search)].reduce((acc, [key, value]) => { 15 | acc[key] = value; 16 | return acc; 17 | }, {}); 18 | } 19 | -------------------------------------------------------------------------------- /public/assets/pages/connectpage/model_backend.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | export default ajax({ 5 | url: "api/backend", 6 | responseType: "json" 7 | }).pipe( 8 | rxjs.map(({ responseJSON }) => responseJSON.result), 9 | rxjs.shareReplay(1), 10 | ); 11 | -------------------------------------------------------------------------------- /public/assets/pages/connectpage/model_config.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | import ajax from "../../lib/ajax.js"; 3 | 4 | export default ajax({ 5 | url: "api/config", 6 | responseType: "json" 7 | }).pipe( 8 | rxjs.map(({ responseJSON }) => responseJSON.result), 9 | rxjs.shareReplay(1), 10 | ); 11 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_adminpage.js: -------------------------------------------------------------------------------- 1 | import { navigate } from "../lib/skeleton/index.js"; 2 | import { toHref } from "../lib/skeleton/router.js"; 3 | import AdminOnly from "./adminpage/decorator_admin_only.js"; 4 | 5 | export default AdminOnly(function() { 6 | navigate(toHref("/admin/backend")); 7 | }); 8 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_connectpage.css: -------------------------------------------------------------------------------- 1 | .component_page_connect{ 2 | background: var(--primary); 3 | height: 100%; 4 | } 5 | .dark-mode .component_page_connect{ 6 | background: var(--bg-color); 7 | } 8 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_logout.js: -------------------------------------------------------------------------------- 1 | import { navigate } from "../lib/skeleton/index.js"; 2 | import { toHref } from "../lib/skeleton/router.js"; 3 | import rxjs, { effect } from "../lib/rx.js"; 4 | 5 | import { deleteSession } from "../model/session.js"; 6 | import { init as setup_config, get as getConfig } from "../model/config.js"; 7 | import ctrlError from "./ctrl_error.js"; 8 | import $loader from "../components/loader.js"; 9 | 10 | export default function(render) { 11 | render($loader); 12 | 13 | effect(deleteSession().pipe( 14 | rxjs.mergeMap(setup_config), 15 | rxjs.tap(() => getConfig("logout") ? location.href = getConfig("logout") : navigate(toHref("/"))), 16 | rxjs.catchError(ctrlError(render)), 17 | )); 18 | } 19 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_notfound.js: -------------------------------------------------------------------------------- 1 | import ctrlError from "./ctrl_error.js"; 2 | import { ApplicationError } from "../lib/error.js"; 3 | 4 | export default function(render) { 5 | ctrlError(render)(new ApplicationError("Not Found", "404 - Not Found")); 6 | } 7 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_sharepage.css: -------------------------------------------------------------------------------- 1 | .component_page_sharelogin { 2 | max-width: 300px; 3 | } 4 | -------------------------------------------------------------------------------- /public/assets/pages/ctrl_viewerpage.css: -------------------------------------------------------------------------------- 1 | .component_page_viewerpage { 2 | width: 100%; 3 | display: flex; 4 | } 5 | .component_page_viewerpage > div { 6 | width: 100%; 7 | display: flex; 8 | flex-direction: column; 9 | } 10 | -------------------------------------------------------------------------------- /public/assets/pages/filespage/ctrl_newitem.css: -------------------------------------------------------------------------------- 1 | .component_newitem { 2 | overflow: hidden; 3 | } 4 | .component_newitem .component_thing { 5 | margin: 2px 0; 6 | } 7 | .component_newitem .component_thing .box { 8 | margin: 0; 9 | } 10 | .component_newitem .component_thing .box .file-details { 11 | flex-grow: 1; 12 | } 13 | .component_newitem .component_thing .box .file-details input { 14 | border-color: var(--border); 15 | padding: 0; 16 | } 17 | .component_newitem .component_thing .box .component_action { 18 | display: block; 19 | opacity: 1; 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/pages/filespage/ctrl_upload.d.ts: -------------------------------------------------------------------------------- 1 | interface HttpContext { 2 | xhr: XMLHttpRequest; 3 | } 4 | 5 | declare function executeHttp( 6 | this: HttpContext, 7 | url: string, 8 | options: { 9 | method: string; 10 | headers: Record; 11 | body: any; 12 | progress: (event: ProgressEvent) => void; 13 | speed: (event: ProgressEvent) => void; 14 | } 15 | ): Promise; 16 | 17 | export function init(); 18 | 19 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/filespage/modal.css: -------------------------------------------------------------------------------- 1 | .component_modal .modal-error-message { 2 | height: 1rem; 3 | margin-top: -5px; 4 | } 5 | .component_modal .modal-error-message:not(:empty) { 6 | animation: shake 0.5s cubic-bezier(.36,.07,.19,.97) both; 7 | transform: translate3d(0, 0, 0); 8 | backface-visibility: hidden; 9 | perspective: 1000px; 10 | } 11 | -------------------------------------------------------------------------------- /public/assets/pages/filespage/state_newthing.js: -------------------------------------------------------------------------------- 1 | import rxjs from "../../lib/rx.js"; 2 | 3 | const action$ = new rxjs.ReplaySubject(1); 4 | action$.next(null); 5 | 6 | export function getAction$() { 7 | return action$.asObservable(); 8 | } 9 | 10 | export function setAction(actionTarget) { 11 | action$.next(actionTarget); 12 | } 13 | -------------------------------------------------------------------------------- /public/assets/pages/filespage/thing.d.ts: -------------------------------------------------------------------------------- 1 | export function init(); 2 | 3 | export function createThing(any): HTMLElement; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_3d.d.ts: -------------------------------------------------------------------------------- 1 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_audio.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | WaveSurfer: { 3 | create: (options: any) => any; 4 | }; 5 | } 6 | 7 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_ebook.css: -------------------------------------------------------------------------------- 1 | .component_ebookviewer .ebookviewer_container { 2 | display: flex; 3 | flex-grow: 1; 4 | min-height: 0; 5 | } 6 | .component_ebookviewer .ebookviewer_container .epub-container { 7 | padding-top: 20px; 8 | padding-bottom: 50px; 9 | box-sizing: border-box; 10 | overflow-x: hidden !important; 11 | } 12 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_ebook.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | ePub: { 3 | Book: new (options: any) => any; 4 | }; 5 | } 6 | 7 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | CodeMirror: { 3 | (element: HTMLElement, options: any): any; 4 | __mode: string; 5 | commands: { 6 | save: (editor: any) => void; 7 | }; 8 | }; 9 | } 10 | 11 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/clike.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/clike/clike.js"; 2 | window.CodeMirror.__mode = "text/x-c++src"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/clojure.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/clojure/clojure.js"; 2 | window.CodeMirror.__mode = "clojure"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/cmake.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/cmake/cmake.js"; 2 | window.CodeMirror.__mode = "cmake"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/commonlisp.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/commonlisp/commonlisp.js"; 2 | window.CodeMirror.__mode = "commonlisp"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/css.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/css/css.js"; 2 | window.CodeMirror.__mode = "css"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/diff.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/diff/diff.js"; 2 | window.CodeMirror.__mode = "diff"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/dockerfile.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/dockerfile/dockerfile.js"; 2 | window.CodeMirror.__mode = "dockerfile"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/elm.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/elm/elm.js"; 2 | window.CodeMirror.__mode = "elm"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/erlang.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/erlang/erlang.js"; 2 | window.CodeMirror.__mode = "erlang"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/go.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/go/go.js"; 2 | window.CodeMirror.__mode = "go"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/groovy.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/groovy/groovy.js"; 2 | window.CodeMirror.__mode = "text/x-groovy"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/htmlmixed.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/htmlmixed/htmlmixed.js"; 2 | window.CodeMirror.__mode = "htmlmixed"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/java.js: -------------------------------------------------------------------------------- 1 | import "./clike.js"; 2 | window.CodeMirror.__mode = "text/x-java"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/javascript.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/javascript/javascript.js"; 2 | window.CodeMirror.__mode = "javascript"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/jsx.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/jsx/jsx.js"; 2 | window.CodeMirror.__mode = "jsx"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/keymap_base.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/keymap/sublime.js"; 2 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/keymap_vim.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/keymap/vim.js"; 2 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/lua.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/lua/lua.js"; 2 | window.CodeMirror.__mode = "lua"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/perl.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/perl/perl.js"; 2 | window.CodeMirror.__mode = "perl"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/php.js: -------------------------------------------------------------------------------- 1 | import "./clike.js"; 2 | import "../../../lib/vendor/codemirror/mode/php/php.js"; 3 | window.CodeMirror.__mode = "php"; 4 | export default window.CodeMirror; 5 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/properties.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/properties/properties.js"; 2 | window.CodeMirror.__mode = "properties"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/python.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/python/python.js"; 2 | window.CodeMirror.__mode = "python"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/r.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/r/r.js"; 2 | window.CodeMirror.__mode = "r"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/ruby.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/ruby/ruby.js"; 2 | window.CodeMirror.__mode = "ruby"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/rust.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/rust/rust.js"; 2 | window.CodeMirror.__mode = "rust"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/sass.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/sass/sass.js"; 2 | window.CodeMirror.__mode = "sass"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/shell.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/shell/shell.js"; 2 | window.CodeMirror.__mode = "shell"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/sparql.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/sparql/sparql.js"; 2 | window.CodeMirror.__mode = "sparql"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/spreadsheet.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/spreadsheet/spreadsheet.js"; 2 | window.CodeMirror.__mode = "spreadsheet"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/sql.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/sql/sql.js"; 2 | window.CodeMirror.__mode = "sql"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/stex.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/stex/stex.js"; 2 | window.CodeMirror.__mode = "stex"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/text.js: -------------------------------------------------------------------------------- 1 | export default window.CodeMirror; 2 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/xml.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/xml/xml.js"; 2 | window.CodeMirror.__mode = "xml"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/yaml-frontmatter.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/gfm/gfm.js"; 2 | import "../../../lib/vendor/codemirror/mode/yaml-frontmatter/yaml-frontmatter.js"; 3 | window.CodeMirror.__mode = "yaml-frontmatter"; 4 | export default window.CodeMirror; 5 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor/yaml.js: -------------------------------------------------------------------------------- 1 | import "../../../lib/vendor/codemirror/mode/yaml/yaml.js"; 2 | window.CodeMirror.__mode = "yaml"; 3 | export default window.CodeMirror; 4 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_editor_orgmode.js: -------------------------------------------------------------------------------- 1 | export default function(editor) { 2 | window.CodeMirror.orgmode.init(editor, (key, value) => { 3 | if (key === "shifttab") { 4 | // org_shifttab(this.state.editor) 5 | // this.props.onFoldChange(value); 6 | } 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_iframe.css: -------------------------------------------------------------------------------- 1 | body:not(.dark-mode) .component_appframe { 2 | background: #525659; 3 | } 4 | 5 | .component_appframe { 6 | text-align: center; 7 | width: 100%; 8 | } 9 | .component_appframe iframe { 10 | width: 100%; 11 | height: 100%; 12 | border: none; 13 | } 14 | .component_appframe .error { 15 | color: white; 16 | font-size: 17px; 17 | margin-top: 10px; 18 | font-family: monospace; 19 | } 20 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_image.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | EXIF: { 3 | getAllTags: (any) => object; 4 | getData: (HTMLElement, any) => void; 5 | }; 6 | } 7 | 8 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_map.css: -------------------------------------------------------------------------------- 1 | #map .leaflet-control-attribution { display: none; } 2 | #map { height: 100%; z-index: 2; } 3 | 4 | #map .leaflet-popup-content-wrapper { 5 | border-radius: 2px; 6 | } 7 | #map .leaflet-popup-content-wrapper, #map .leaflet-popup-tip { 8 | box-shadow: 0 3px 14px rgba(0,0,0,0.15); 9 | } 10 | #map .leaflet-control-layers-list { user-select: none; } 11 | 12 | #map .leaflet-control-measure .leaflet-control-measure-toggle { opacity: 0.6; } 13 | #map .leaflet-control-scale { 14 | margin-left: 10px; 15 | margin-bottom: 10px; 16 | } 17 | #map .leaflet-popup-content { 18 | margin: 10px 20px 10px 15px; 19 | } 20 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_map.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | L: any; 3 | } 4 | 5 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_pdf.css: -------------------------------------------------------------------------------- 1 | .component_page_viewerpage .component_pdfviewer { 2 | background: #525659; 3 | text-align:center; 4 | } 5 | .component_page_viewerpage .component_pdfviewer [data-bind="pdf"] { 6 | overflow-y: scroll; 7 | flex: 1 1 auto; 8 | } 9 | .component_page_viewerpage .component_pdfviewer [data-bind="pdf"] embed { 10 | width:100%; 11 | height:100%; 12 | } 13 | .component_page_viewerpage .component_pdfviewer [data-bind="pdf"] component-icon[name="loading"] { 14 | padding-top: 75px; 15 | display: block; 16 | } 17 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_pdf.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | pdfjsLib: { 3 | getDocument: (url: string) => { promise: Promise }; 4 | GlobalWorkerOptions: { 5 | workerSrc: string; 6 | }; 7 | // Add other properties and methods of pdfjsLib as needed 8 | }; 9 | env?: string; 10 | chrome: object; 11 | } 12 | 13 | export default function(any): void; -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/application_skeleton.css: -------------------------------------------------------------------------------- 1 | .component_skeletonviewer { 2 | background: #52565911; 3 | } 4 | .component_skeleton_container { 5 | height: 100%; 6 | width: 100%; 7 | } 8 | 9 | .component_skeleton_container > .component_loader { 10 | width: 100%; 11 | } 12 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/common.js: -------------------------------------------------------------------------------- 1 | import { fromHref } from "../../lib/skeleton/router.js"; 2 | import { transition as transitionLib, slideYIn } from "../../lib/animate.js"; 3 | import { basename, forwardURLParams } from "../../lib/path.js"; 4 | 5 | export function transition($node) { 6 | return transitionLib($node, { timeEnter: 150, enter: slideYIn(2) }); 7 | } 8 | 9 | export function getFilename() { 10 | return basename(getCurrentPath()) || " "; 11 | } 12 | 13 | export function getDownloadUrl() { 14 | return forwardURLParams("api/files/cat?path=" + encodeURIComponent(getCurrentPath()), ["share"]); 15 | } 16 | 17 | export function getCurrentPath() { 18 | const fullpath = fromHref(location.pathname + location.hash); 19 | return decodeURIComponent(fullpath.replace(new RegExp("^/view"), "")); 20 | } 21 | -------------------------------------------------------------------------------- /public/assets/pages/viewerpage/common_player.js: -------------------------------------------------------------------------------- 1 | export function formatTimecode(seconds) { 2 | return String(Math.floor(seconds / 60)).padStart(2, "0") + 3 | ":" + 4 | String(Math.floor(seconds % 60)).padStart(2, "0"); 5 | } 6 | 7 | // TODO: abstract setVolume, setSeek and setStatus 8 | -------------------------------------------------------------------------------- /public/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | chrome: any; 3 | cast: any; 4 | overrides: { 5 | [key: string]: any; 6 | "xdg-open"?: (mime: string) => void; 7 | }; 8 | BEARER_TOKEN?: string; 9 | } -------------------------------------------------------------------------------- /public/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from "vitest/config"; 2 | 3 | export default defineConfig(({ comand, mode }) => { 4 | return { 5 | plugins: [], 6 | test: { 7 | global: true, 8 | environment: "jsdom", 9 | setupFiles: ["./vite.setup.js"], 10 | } 11 | }; 12 | }); 13 | -------------------------------------------------------------------------------- /public/vite.setup.js: -------------------------------------------------------------------------------- 1 | import { 2 | describe, it, test, expect, vi, 3 | afterEach, afterAll, beforeEach, beforeAll, 4 | } from "vitest"; 5 | 6 | global.nextTick = () => new Promise((done) => setTimeout(done, 0)); 7 | global.requestAnimationFrame = (callback) => setTimeout(callback, 0); 8 | 9 | global.describe = describe; 10 | global.it = it; 11 | global.test = test; 12 | global.expect = expect; 13 | global.vi = vi; 14 | global.beforeEach = beforeEach; 15 | global.beforeAll = beforeAll; 16 | global.afterEach = afterEach; 17 | global.afterAll = afterAll; 18 | -------------------------------------------------------------------------------- /server/.assets/emacs/README.md: -------------------------------------------------------------------------------- 1 | Those are the required dependencies for emacs used in the org-mode export feature. They are getting pulled from [the Dockerfile](https://raw.githubusercontent.com/mickael-kerjean/filestash/master/docker/Dockerfile). 2 | -------------------------------------------------------------------------------- /server/common/app.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "context" 5 | ) 6 | 7 | type App struct { 8 | Backend IBackend 9 | Body map[string]interface{} 10 | Session map[string]string 11 | Share Share 12 | Context context.Context 13 | Authorization string 14 | Languages []string 15 | } 16 | -------------------------------------------------------------------------------- /server/common/debug.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "fmt" 5 | "runtime" 6 | ) 7 | 8 | func PrintMemUsage() { 9 | var m runtime.MemStats 10 | runtime.ReadMemStats(&m) 11 | // For info on each, see: https://golang.org/pkg/runtime/#MemStats 12 | fmt.Printf("Alloc = %v MiB", bToMb(m.Alloc)) 13 | fmt.Printf("\tTotalAlloc = %v MiB", bToMb(m.TotalAlloc)) 14 | fmt.Printf("\tSys = %v MiB", bToMb(m.Sys)) 15 | fmt.Printf("\tObjects = %d", m.HeapObjects) 16 | fmt.Printf("\tNumGC = %v\n", m.NumGC) 17 | } 18 | 19 | func bToMb(b uint64) uint64 { 20 | return b / 1024 / 1024 21 | } 22 | -------------------------------------------------------------------------------- /server/common/dummy.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "io" 5 | slog "log" 6 | ) 7 | 8 | func NewNilLogger() *slog.Logger { 9 | return slog.New(dummyWriter{}, "", slog.LstdFlags) 10 | } 11 | 12 | type dummyWriter struct { 13 | io.Writer 14 | } 15 | 16 | func (this dummyWriter) Write(p []byte) (n int, err error) { 17 | return len(p), nil 18 | } 19 | -------------------------------------------------------------------------------- /server/common/files_all.go: -------------------------------------------------------------------------------- 1 | // +build !linux 2 | 3 | package common 4 | 5 | import ( 6 | "os" 7 | ) 8 | 9 | func SafeOsOpenFile(path string, flag int, perm os.FileMode) (*os.File, error) { 10 | if err := safePath(path); err != nil { 11 | Log.Debug("common::files safeOsOpenFile err[%s] path[%s]", err.Error(), path) 12 | return nil, ErrFilesystemError 13 | } 14 | return os.OpenFile(path, flag, perm) 15 | } 16 | -------------------------------------------------------------------------------- /server/common/files_linux.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "errors" 5 | "io/fs" 6 | "os" 7 | "syscall" 8 | ) 9 | 10 | func SafeOsOpenFile(path string, flag int, perm os.FileMode) (*os.File, error) { 11 | if err := safePath(path); err != nil { 12 | Log.Debug("common::files safeOsOpenFile err[%s] path[%s]", err.Error(), path) 13 | return nil, ErrFilesystemError 14 | } 15 | f, err := os.OpenFile(path, flag|syscall.O_NOFOLLOW, perm) 16 | if err != nil { 17 | if errors.Is(err, fs.ErrNotExist) { 18 | return nil, ErrNotFound 19 | } 20 | return nil, processError(err) 21 | } 22 | return f, err 23 | } 24 | -------------------------------------------------------------------------------- /server/common/mime.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "path/filepath" 5 | "strings" 6 | ) 7 | 8 | //go:generate sh -c "go run ../generator/mime.go > mime_generated.go && go fmt mime_generated.go" 9 | var MimeTypes map[string]string = make(map[string]string, 0) 10 | 11 | func GetMimeType(p string) string { 12 | ext := filepath.Ext(p) 13 | if ext != "" { 14 | ext = ext[1:] 15 | } 16 | ext = strings.ToLower(ext) 17 | mType := MimeTypes[ext] 18 | if mType == "" { 19 | return "application/octet-stream" 20 | } 21 | return mType 22 | } 23 | 24 | func AllMimeTypes() map[string]string { 25 | return MimeTypes 26 | } 27 | -------------------------------------------------------------------------------- /server/common/recovery.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | // previous cookie configuration in canary release of 2024/10 break existing cookie and 8 | // can introduce weird error when a user has things in cache. 9 | // this code will deprecate early 2025 10 | func RecoverFromBadCookie(res http.ResponseWriter) { 11 | Log.Debug("common::recovery exec=RecoverFromBadCookie") 12 | http.SetCookie(res, &http.Cookie{ 13 | Name: "auth", 14 | Value: "", 15 | MaxAge: -1, 16 | HttpOnly: true, 17 | SameSite: http.SameSiteStrictMode, 18 | Path: WithBase("/api/"), 19 | Secure: false, 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /server/common/ssl/index.go: -------------------------------------------------------------------------------- 1 | package ssl 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | ) 6 | 7 | var ( 8 | keyPEMPath func() string 9 | certPEMPath func() string 10 | ) 11 | 12 | func init() { 13 | keyPEMPath = func() string { 14 | return GetAbsolutePath(CERT_PATH, "key.pem") 15 | } 16 | certPEMPath = func() string { 17 | return GetAbsolutePath(CERT_PATH, "cert.pem") 18 | } 19 | } 20 | 21 | func Clear() { 22 | clearPrivateKey() 23 | clearCert() 24 | } 25 | -------------------------------------------------------------------------------- /server/common/token.go: -------------------------------------------------------------------------------- 1 | package common 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | const ( 8 | ADMIN_CLAIM = "ADMIN" 9 | ) 10 | 11 | type AdminToken struct { 12 | Claim string `json:"token"` 13 | Expire time.Time `json:"time"` 14 | } 15 | 16 | func NewAdminToken() AdminToken { 17 | return AdminToken{ 18 | Claim: ADMIN_CLAIM, 19 | Expire: time.Now().Add(time.Hour * 24), 20 | } 21 | } 22 | 23 | func (this AdminToken) IsAdmin() bool { 24 | if this.Claim != ADMIN_CLAIM { 25 | return false 26 | } 27 | return true 28 | } 29 | 30 | func (this AdminToken) IsValid() bool { 31 | if this.Expire.Sub(time.Now()) <= 0 { 32 | return false 33 | } 34 | return true 35 | } 36 | -------------------------------------------------------------------------------- /server/ctrl/config.go: -------------------------------------------------------------------------------- 1 | package ctrl 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | "io/ioutil" 6 | "net/http" 7 | ) 8 | 9 | var configpath = GetAbsolutePath(CONFIG_PATH, "config.json") 10 | 11 | func PrivateConfigHandler(ctx *App, res http.ResponseWriter, req *http.Request) { 12 | SendSuccessResult(res, &Config) 13 | } 14 | 15 | func PrivateConfigUpdateHandler(ctx *App, res http.ResponseWriter, req *http.Request) { 16 | b, _ := ioutil.ReadAll(req.Body) 17 | if err := SaveConfig(b); err != nil { 18 | SendErrorResult(res, err) 19 | return 20 | } 21 | Config.Load() 22 | SendSuccessResult(res, nil) 23 | } 24 | 25 | func PublicConfigHandler(ctx *App, res http.ResponseWriter, req *http.Request) { 26 | cfg := Config.Export() 27 | SendSuccessResultWithEtagAndGzip(res, req, cfg) 28 | } 29 | -------------------------------------------------------------------------------- /server/ctrl/static/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 404 4 | 5 | 6 |
7 |

404

8 |

Page Not Found

9 |
10 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /server/generator/constants.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | "os/exec" 7 | "strings" 8 | "time" 9 | ) 10 | 11 | func main() { 12 | cmd, b := exec.Command("git", "rev-parse", "HEAD"), new(strings.Builder) 13 | cmd.Stdout = b 14 | cmd.Run() 15 | 16 | f, err := os.OpenFile("../common/constants_generated.go", os.O_CREATE|os.O_WRONLY, os.ModePerm) 17 | if err != nil { 18 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 19 | os.Exit(1) 20 | return 21 | } 22 | f.Write([]byte(fmt.Sprintf(` 23 | package common 24 | 25 | func init() { 26 | BUILD_REF = "%s" 27 | BUILD_DATE = "%s" 28 | } 29 | `, strings.TrimSpace(b.String()), time.Now().Format("20060102")))) 30 | f.Close() 31 | } 32 | -------------------------------------------------------------------------------- /server/generator/emacs-el.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "os" 7 | ) 8 | 9 | func main() { 10 | f, err := os.OpenFile("../../config/emacs.el", os.O_RDONLY, os.ModePerm) 11 | if err != nil { 12 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 13 | os.Exit(1) 14 | return 15 | } 16 | defer f.Close() 17 | 18 | j, err := ioutil.ReadAll(f) 19 | if err != nil { 20 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 21 | os.Exit(1) 22 | } 23 | 24 | f, err = os.OpenFile("./export_generated.go", os.O_CREATE|os.O_WRONLY, os.ModePerm) 25 | if err != nil { 26 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 27 | os.Exit(1) 28 | return 29 | } 30 | f.Write([]byte(fmt.Sprintf(`package ctrl 31 | 32 | func init() { 33 | EmacsElConfig = `+"`"+` 34 | %s 35 | `+"`"+` 36 | } 37 | `, j))) 38 | f.Close() 39 | } 40 | -------------------------------------------------------------------------------- /server/generator/mime.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "io/ioutil" 7 | "os" 8 | ) 9 | 10 | func main() { 11 | f, err := os.OpenFile("../../config/mime.json", os.O_RDONLY, os.ModePerm) 12 | if err != nil { 13 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 14 | os.Exit(1) 15 | return 16 | } 17 | defer f.Close() 18 | 19 | j, err := ioutil.ReadAll(f) 20 | if err != nil { 21 | fmt.Fprintf(os.Stderr, "error: %v\n", err) 22 | os.Exit(1) 23 | } 24 | mTypes := make(map[string]string, 0) 25 | json.Unmarshal(j, &mTypes) 26 | 27 | fmt.Printf("package common\n") 28 | fmt.Printf("func init() {\n") 29 | for key, value := range mTypes { 30 | fmt.Printf("MimeTypes[\"%s\"] = \"%s\"\n", key, value) 31 | } 32 | fmt.Printf("}\n") 33 | 34 | } 35 | -------------------------------------------------------------------------------- /server/model/formater/README.md: -------------------------------------------------------------------------------- 1 | This is a bare bone utilities to convert a stream onto text for full text search purpose. 2 | There's some other alternative but none of them run with a small footprint. 3 | 4 | At the moment it supports: 5 | - office documents 6 | - pdf (TODO: remove dependency on pdftotext) 7 | - text base files 8 | -------------------------------------------------------------------------------- /server/model/formater/pdf.go: -------------------------------------------------------------------------------- 1 | package formater 2 | 3 | import ( 4 | "bytes" 5 | "fmt" 6 | . "github.com/mickael-kerjean/filestash/server/common" 7 | "io" 8 | "math/rand" 9 | "os" 10 | "os/exec" 11 | ) 12 | 13 | func PdfFormater(r io.ReadCloser) (io.ReadCloser, error) { 14 | tmpName := fmt.Sprintf("/tmp/pdf_%d.docx", rand.Intn(1000000)) 15 | defer os.Remove(tmpName) 16 | f, err := os.OpenFile(tmpName, os.O_CREATE|os.O_WRONLY, os.ModePerm) 17 | if err != nil { 18 | return nil, err 19 | } 20 | _, err = io.Copy(f, r) 21 | if err != nil { 22 | f.Close() 23 | return nil, err 24 | } 25 | f.Close() 26 | 27 | cmd := exec.Command("pdftotext", tmpName, "-") 28 | out := bytes.NewBuffer([]byte{}) 29 | cmd.Stdout = out 30 | err = cmd.Run() 31 | if err != nil { 32 | return nil, err 33 | } 34 | return NewReadCloserFromReader(out), nil 35 | } 36 | -------------------------------------------------------------------------------- /server/model/formater/txt.go: -------------------------------------------------------------------------------- 1 | package formater 2 | 3 | import ( 4 | "io" 5 | ) 6 | 7 | func TxtFormater(rc io.ReadCloser) (io.ReadCloser, error) { 8 | return rc, nil 9 | } 10 | -------------------------------------------------------------------------------- /server/model/permissions.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | ) 6 | 7 | func CanRead(ctx *App) bool { 8 | if ctx.Share.Id != "" { 9 | return ctx.Share.CanRead 10 | } 11 | return true 12 | } 13 | 14 | func CanEdit(ctx *App) bool { 15 | if ctx.Share.Id != "" { 16 | return ctx.Share.CanWrite 17 | } 18 | return true 19 | } 20 | 21 | func CanUpload(ctx *App) bool { 22 | if ctx.Share.Id != "" { 23 | return ctx.Share.CanUpload 24 | } 25 | return true 26 | } 27 | 28 | func CanShare(ctx *App) bool { 29 | if ctx.Share.Id != "" { 30 | return ctx.Share.CanShare 31 | } 32 | return true 33 | } 34 | -------------------------------------------------------------------------------- /server/plugin/plg_application_3d/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make install 3 | 4 | install: 5 | zip -r application_3d.zip . 6 | mv application_3d.zip ../../../dist/data/state/plugins/application_3d.zip 7 | 8 | deps_mesh: 9 | [ -d vendor ] || mkdir vendor 10 | curl https://gist.githubusercontent.com/mickael-kerjean/9a517f95112410fcacaad8563c1ba314/raw/ab483b38aebb7048832aad7b342f9161dd928e49/gistfile1.txt > vendor/MeshLoader.js 11 | -------------------------------------------------------------------------------- /server/plugin/plg_application_3d/index_fbx.js: -------------------------------------------------------------------------------- 1 | export default async function(I3D, { THREE }) { 2 | const module = await import("./vendor/FBXLoader.js"); 3 | 4 | return class Impl extends I3D { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | load(url, onLoad, onProgress, onError) { 10 | return (new module.FBXLoader()).load(url, onLoad, onProgress, onError); 11 | } 12 | 13 | transform(obj) { 14 | obj.name = "All"; 15 | return obj; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /server/plugin/plg_application_3d/index_gltf.js: -------------------------------------------------------------------------------- 1 | export default async function(I3D, { THREE }) { 2 | const module = await import("./vendor/GLTFLoader.js"); 3 | 4 | return class Impl extends I3D { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | load(url, onLoad, onProgress, onError) { 10 | return new module.GLTFLoader().load(url, onLoad, onProgress, onError); 11 | } 12 | 13 | transform(gltf) { 14 | const mesh = gltf.scene; 15 | mesh.animations = gltf.animations; 16 | return mesh; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/plugin/plg_application_3d/index_mesh.js: -------------------------------------------------------------------------------- 1 | export default async function(I3D, { THREE }) { 2 | const module = await import("./vendor/MeshLoader.js"); 3 | 4 | return class Impl extends I3D { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | load(url, onLoad, onProgress, onError) { 10 | return (new module.MeshLoader()).load(url, onLoad, onProgress, onError); 11 | } 12 | 13 | transform(obj) { 14 | return obj; 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /server/plugin/plg_application_3d/index_stl.js: -------------------------------------------------------------------------------- 1 | export default async function(I3D, { THREE }) { 2 | const module = await import("./vendor/STLLoader.js"); 3 | 4 | return class Impl extends I3D { 5 | constructor() { 6 | super(); 7 | } 8 | 9 | load(url, onLoad, onProgress, onError) { 10 | return (new module.STLLoader()).load(url, onLoad, onProgress, onError); 11 | } 12 | 13 | transform(geometry) { 14 | const material = new THREE.MeshPhongMaterial({ 15 | emissive: 0x40464b, 16 | specular: 0xf9f9fa, 17 | shininess: 15, 18 | transparent: true, 19 | }); 20 | if (geometry.hasColors) material.vertexColors = true; 21 | else material.color = material.emissive; 22 | return new THREE.Mesh(geometry, material); 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /server/plugin/plg_application_dev/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make build 3 | make install 4 | make clean 5 | 6 | build: 7 | emcc -O2 -c loader_symbol.c 8 | emcc --no-entry loader_symbol.o -o loader_symbol.wasm 9 | 10 | install: 11 | zip -r application_dev.zip . 12 | mv application_dev.zip ../../../dist/data/state/plugins/ 13 | 14 | clean: 15 | rm *.o *.wasm 16 | -------------------------------------------------------------------------------- /server/plugin/plg_application_dev/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Filestash Pty Ltd", 3 | "version": "v0.0", 4 | "modules": [ 5 | { 6 | "type": "xdg-open", 7 | "mime": "application/x-archive", 8 | "application": "table" 9 | } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_application_map/Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | make install 3 | 4 | install: 5 | zip -r application_map.zip . 6 | mv application_map.zip ../../../dist/data/state/plugins/ 7 | -------------------------------------------------------------------------------- /server/plugin/plg_application_map/constant.js: -------------------------------------------------------------------------------- 1 | export const PLUGINS = [ 2 | "plugin_grayscale", 3 | ]; 4 | export const DEFAULT_TILE_SERVER = "https://tile.openstreetmap.org/{z}/{x}/{y}.png"; 5 | -------------------------------------------------------------------------------- /server/plugin/plg_application_map/index_geojson.js: -------------------------------------------------------------------------------- 1 | import { PLUGINS, DEFAULT_TILE_SERVER } from "./constant.js"; 2 | 3 | export default async function(IMap) { 4 | const plugins = await Promise.all(PLUGINS.map((name) => import(`./plugins/${name}.js`))); 5 | 6 | return class MapImpl extends IMap { 7 | constructor(response, { map, $page }) { 8 | super(); 9 | this.response = JSON.parse(new TextDecoder().decode(response)); 10 | 11 | window.L.tileLayer(DEFAULT_TILE_SERVER, { maxZoom: 21 }).addTo(map); 12 | plugins.forEach((plugin) => plugin.default({ map, $page })); 13 | } 14 | 15 | async toGeoJSON() { 16 | return this.response; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /server/plugin/plg_application_map/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "author": "Filestash Pty Ltd", 3 | "version": "v0.0", 4 | "modules": [ 5 | { 6 | "type": "xdg-open", 7 | "mime": "application/geo+json", 8 | "entrypoint": "/index_geojson.js", 9 | "application": "map" 10 | }, 11 | { 12 | "type": "xdg-open", 13 | "mime": "application/vnd.ogc.wms_xml", 14 | "entrypoint": "/index_wms.js", 15 | "application": "map" 16 | }, 17 | { 18 | "type": "xdg-open", 19 | "mime": "application/gpx+xml", 20 | "entrypoint": "/index_gpx.js", 21 | "application": "map" 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /server/plugin/plg_application_map/plugins/plugin_grayscale.js: -------------------------------------------------------------------------------- 1 | import { createElement } from "../../../assets/lib/skeleton/index.js"; 2 | 3 | const PERCENT = "85%"; 4 | 5 | export default async function({ $page }) { 6 | $page.appendChild(createElement(` 7 | 8 | `)); 9 | } 10 | -------------------------------------------------------------------------------- /server/plugin/plg_authenticate_htpasswd/deps/crypt/AUTHORS.md: -------------------------------------------------------------------------------- 1 | ### Initial author 2 | 3 | [Jeramey Crawford](https://github.com/jeramey) 4 | 5 | ### Other authors 6 | 7 | [Jonas mg](https://github.com/tredoe) 8 | 9 | -------------------------------------------------------------------------------- /server/plugin/plg_authenticate_htpasswd/deps/crypt/common/doc.go: -------------------------------------------------------------------------------- 1 | // Copyright 2012, Jeramey Crawford 2 | // Copyright 2013, Jonas mg 3 | // All rights reserved. 4 | // 5 | // Use of this source code is governed by a BSD-style license 6 | // that can be found in the LICENSE file. 7 | 8 | // Package common contains routines used by multiple password hashing 9 | // algorithms. 10 | // 11 | // Generally, you will never import this package directly. Many of the 12 | // *_crypt packages will import this package if they require it. 13 | package common 14 | -------------------------------------------------------------------------------- /server/plugin/plg_authenticate_local/utils.go: -------------------------------------------------------------------------------- 1 | package plg_authenticate_local 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | func formatRole(s string) string { 8 | arr := strings.Split(strings.ToLower(s), ",") 9 | for i := range arr { 10 | arr[i] = strings.TrimSpace(strings.ToLower(arr[i])) 11 | } 12 | return strings.Join(arr, ", ") 13 | } 14 | 15 | func formatEmail(s string) string { 16 | return strings.TrimSpace(strings.ToLower(s)) 17 | } 18 | 19 | func formatPassword(s string) string { 20 | return strings.TrimSpace(s) 21 | } 22 | -------------------------------------------------------------------------------- /server/plugin/plg_backend_nfs4/repo/README.md: -------------------------------------------------------------------------------- 1 | TODO: we can't go get github.com/kha7iq/go-nfs-client => fork over and fix it instead 2 | -------------------------------------------------------------------------------- /server/plugin/plg_backend_nfs4/repo/internal/cleanuper.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | type cleanuper struct { 4 | cleanupErr func() error 5 | cleanup func() 6 | } 7 | 8 | func NewCleanupErr(cl func() error) *cleanuper { 9 | return &cleanuper{cleanupErr: cl} 10 | } 11 | 12 | func NewCleanup(cl func()) *cleanuper { 13 | return &cleanuper{cleanup: cl} 14 | } 15 | 16 | func (c *cleanuper) Disarm() { 17 | c.cleanupErr = nil 18 | c.cleanup = nil 19 | } 20 | 21 | func (c *cleanuper) Cleanup() { 22 | if c.cleanupErr != nil { 23 | _ = c.cleanupErr() 24 | } 25 | 26 | if c.cleanup != nil { 27 | c.cleanup() 28 | } 29 | } 30 | 31 | -------------------------------------------------------------------------------- /server/plugin/plg_backend_nfs4/repo/internal/nfsconst.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | /* 4 | const OPEN4_SHARE_ACCESS_READ = 0x00000001 5 | 6 | const OPEN4_SHARE_ACCESS_WRITE = 0x00000002 7 | 8 | const OPEN4_SHARE_ACCESS_BOTH = 0x00000003 9 | 10 | const OPEN4_SHARE_DENY_NONE = 0x00000000 11 | 12 | const OPEN4_SHARE_DENY_READ = 0x00000001 13 | 14 | const OPEN4_SHARE_DENY_WRITE = 0x00000002 15 | 16 | const OPEN4_SHARE_DENY_BOTH = 0x00000003 17 | */ 18 | -------------------------------------------------------------------------------- /server/plugin/plg_backend_nfs4/repo/internal/types.go: -------------------------------------------------------------------------------- 1 | package internal 2 | 3 | //goland:noinspection GoSnakeCaseUsage 4 | type Uint32_t = uint32 5 | //goland:noinspection GoSnakeCaseUsage 6 | type Uint64_t = uint64 7 | //goland:noinspection GoSnakeCaseUsage 8 | type Int64_t = int64 9 | 10 | //goland:noinspection GoSnakeCaseUsage 11 | type XDR_Uint32_t = *XdrUint32 12 | //goland:noinspection GoSnakeCaseUsage 13 | type XdrType_Uint32_t = XdrType_uint32 14 | //goland:noinspection GoSnakeCaseUsage 15 | type XDR_Uint64_t = *XdrUint64 16 | //goland:noinspection GoSnakeCaseUsage 17 | type XdrType_Uint64_t = XdrType_uint64 18 | //goland:noinspection GoSnakeCaseUsage 19 | type XdrType_Int64_t = XdrType_int64 20 | //goland:noinspection GoSnakeCaseUsage 21 | type XDR_Int64_t = *XdrInt64 22 | 23 | func MinUint64(i1, i2 uint64) uint64 { 24 | if i1 < i2 { 25 | return i1 26 | } 27 | return i2 28 | } -------------------------------------------------------------------------------- /server/plugin/plg_editor_wopi/index.go: -------------------------------------------------------------------------------- 1 | package plg_editor_wopi 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | ) 6 | 7 | func init() { 8 | Hooks.Register.Onload(func() { 9 | server_url() 10 | origin() 11 | rewrite_url() 12 | if plugin_enable() { 13 | Hooks.Register.XDGOpen(WOPIOverrides) 14 | } 15 | }) 16 | Hooks.Register.HttpEndpoint(WOPIRoutes) 17 | } 18 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_console/index.go: -------------------------------------------------------------------------------- 1 | package plg_handler_console 2 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_console/src/app.css: -------------------------------------------------------------------------------- 1 | html{ height: 100%; } 2 | body{ margin: 0; height: 100%; padding: 10px 0 0px 10px; box-sizing: border-box; } 3 | #terminal{ height: 100%; } 4 | #error-message{ 5 | text-align: center; 6 | font-size: 1.5em; 7 | color: #333; 8 | } 9 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/README.md: -------------------------------------------------------------------------------- 1 | This is a MCP plugin acting as an interface for AI agent to do stuff on a remote storage you have configured in Filestash, be it a FTP server, SFTP, S3, WebDAV, SMB, GIT, NFS, .... 2 | 3 | demo server: https://demo.filestash.app/sse 4 | release note: https://www.filestash.app/2025/04/01/mcp-feature/ 5 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/config/config.go: -------------------------------------------------------------------------------- 1 | package plg_handler_mcp 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | ) 6 | 7 | var PluginEnable = func() bool { 8 | return Config.Get("features.mcp.enable").Schema(func(f *FormElement) *FormElement { 9 | if f == nil { 10 | f = &FormElement{} 11 | } 12 | f.Name = "enable" 13 | f.Type = "enable" 14 | f.Target = []string{"mcp_can_edit"} 15 | f.Description = "Enable/Disable the Model Context Protocol" 16 | f.Default = false 17 | return f 18 | }).Bool() 19 | } 20 | 21 | var CanEdit = func() bool { 22 | return Config.Get("features.mcp.can_edit").Schema(func(f *FormElement) *FormElement { 23 | if f == nil { 24 | f = &FormElement{} 25 | } 26 | f.Id = "mcp_can_edit" 27 | f.Name = "can_edit" 28 | f.Type = "boolean" 29 | f.Description = "Enable/Disable editing" 30 | f.Default = false 31 | return f 32 | }).Bool() 33 | } 34 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/impl/resources.go: -------------------------------------------------------------------------------- 1 | package impl 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/plugin/plg_handler_mcp/types" 5 | ) 6 | 7 | func AllResources() []Resource { 8 | return []Resource{} 9 | } 10 | 11 | func AllResourceTemplates() []ResourceTemplate { 12 | return []ResourceTemplate{} 13 | } 14 | 15 | func ExecResourceRead(params map[string]any) []ResourceContent { 16 | return []ResourceContent{} 17 | } 18 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/mcp_completion.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type CallCompletionResult struct { 4 | Completion Completion `json:"completion"` 5 | } 6 | 7 | type Completion struct { 8 | Values []string `json:"values"` 9 | Total uint64 `json:"total"` 10 | HasMore bool `json:"hasMore"` 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/mcp_init.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type InitializeResult struct { 4 | ProtocolVersion string `json:"protocolVersion"` 5 | ServerInfo ServerInfo `json:"serverInfo"` 6 | Capabilities Capabilities `json:"capabilities"` 7 | } 8 | 9 | type ServerInfo struct { 10 | Name string `json:"name"` 11 | Version string `json:"version"` 12 | } 13 | 14 | type Capabilities struct { 15 | Tools map[string]interface{} `json:"tools",omitempty` 16 | Resources map[string]interface{} `json:"resources",omitempty` 17 | Prompts map[string]interface{} `json:"prompts",omitempty` 18 | } 19 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/mcp_notification.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | var ( 4 | ErrToolsListChanges = newError("notifications/tools/list_changed") 5 | ErrDisconnect = newError("internal/disconnect") 6 | ) 7 | 8 | func newError(s string) error { 9 | return notification{s} 10 | } 11 | 12 | type notification struct { 13 | msg string 14 | } 15 | 16 | func (this notification) Error() string { 17 | return this.msg 18 | } 19 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/mcp_prompts.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | type CallPromptsList struct { 4 | Prompts []Prompt `json:"prompts"` 5 | NextCursor string `json:"nextCursor",omitempty` 6 | } 7 | 8 | type Prompt struct { 9 | Name string `json:"name"` 10 | Description string `json:"description"` 11 | Arguments []PromptArgument `json:"arguments"` 12 | } 13 | 14 | type PromptArgument struct { 15 | Name string `json:"name"` 16 | Description string `json:"description"` 17 | Required bool `json:"required"` 18 | } 19 | 20 | type CallPromptGet struct { 21 | Description string `json:"description"` 22 | Messages []PromptMessage `json:"messages"` 23 | } 24 | 25 | type PromptMessage struct { 26 | Role string `json:"role"` 27 | Content TextContent `json:"content"` 28 | } 29 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/mcp_tools.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | type CallListTools struct { 8 | Tools []Tool `json:"tools"` 9 | } 10 | 11 | type Tool struct { 12 | Name string `json:"name"` 13 | Description string `json:"description"` 14 | InputSchema json.RawMessage `json:"inputSchema"` 15 | } 16 | 17 | type CallTool struct { 18 | Content []TextContent `json:"content"` 19 | } 20 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/resources.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import "encoding/json" 4 | 5 | type IResource interface { 6 | Resource() ([]json.RawMessage, error) 7 | } 8 | 9 | type TextContent struct { 10 | Type string `json:"type"` 11 | Text string `json:"text"` 12 | } 13 | 14 | type BinaryContent struct { 15 | URI string `json:uri"` 16 | MimeType string `json:"mimeType"` 17 | Blob []byte `json:"blob"` 18 | } 19 | 20 | func (this TextContent) Resource() ([]byte, error) { 21 | return json.Marshal(this) 22 | } 23 | 24 | func (this BinaryContent) Resource() ([]byte, error) { 25 | return json.Marshal(this) 26 | } 27 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/types/session.go: -------------------------------------------------------------------------------- 1 | package types 2 | 3 | import ( 4 | "time" 5 | 6 | . "github.com/mickael-kerjean/filestash/server/common" 7 | ) 8 | 9 | type UserSession struct { 10 | Id string 11 | Chan chan JSONRPCRequest 12 | HomeDir string 13 | CurrDir string 14 | Token string 15 | Backend IBackend 16 | Ping Ping 17 | } 18 | 19 | type Ping struct { 20 | ID uint64 21 | LastResponse time.Time 22 | } 23 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/utils/cors.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "net/http" 5 | ) 6 | 7 | func WithCors(w http.ResponseWriter) { 8 | w.Header().Set("Access-Control-Allow-Origin", "*") 9 | w.Header().Set("Access-Control-Allow-Headers", "mcp-protocol-version, Content-Type") 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/utils/default.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "fmt" 5 | ) 6 | 7 | func ToString(val any, def string) string { 8 | if val == nil { 9 | return def 10 | } else if val == "" { 11 | return def 12 | } 13 | return fmt.Sprintf("%v", val) 14 | } 15 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/utils/json.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "encoding/json" 5 | ) 6 | 7 | func JsonSchema(in any) json.RawMessage { 8 | b, _ := json.Marshal(in) 9 | return json.RawMessage(b) 10 | } 11 | 12 | func JsonText(in any) string { 13 | b, _ := json.MarshalIndent(in, "", " ") 14 | return string(b) 15 | } 16 | -------------------------------------------------------------------------------- /server/plugin/plg_handler_mcp/utils/mcp.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | func GetArgumentsString(params map[string]any, name string) string { 4 | m, ok := params["arguments"].(map[string]any) 5 | if !ok { 6 | return "" 7 | } 8 | p, ok := m[name].(string) 9 | if !ok { 10 | return "" 11 | } 12 | return p 13 | } 14 | 15 | func GetArgumentString(params map[string]any, name string) string { 16 | m, ok := params["argument"].(map[string]any) 17 | if !ok { 18 | return "" 19 | } 20 | p, ok := m[name].(string) 21 | if !ok { 22 | return "" 23 | } 24 | return p 25 | } 26 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_gif.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_gif.h" 4 | // #cgo LDFLAGS: -l:libgif.a -l:libwebp.a 5 | import "C" 6 | 7 | func gif(input uintptr, output uintptr, size int) { 8 | C.gif_to_webp(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_gif.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int gif_to_webp(int inputDesc, int outputDesc, int targetSize); 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_gif_vendor.h: -------------------------------------------------------------------------------- 1 | #define FILE_STATE_READ 0x08 2 | #define IS_READABLE(Private) (Private->FileState & FILE_STATE_READ) 3 | #define INT_MAX 2147483647 4 | 5 | typedef struct GifFilePrivateType { 6 | GifWord FileState; 7 | FILE *File; 8 | } GifFilePrivateType; 9 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_jpeg.h: -------------------------------------------------------------------------------- 1 | int jpeg_to_jpeg(int input, int output, int targetSize); 2 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_jpeg_freebsd.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_jpeg.h" 4 | // #cgo LDFLAGS: -L /usr/local/lib -L /usr/lib -L /lib -l:libjpeg.a 5 | // #cgo CFLAGS: -I /usr/local/include 6 | import "C" 7 | 8 | func jpeg(input uintptr, output uintptr, size int) { 9 | C.jpeg_to_jpeg(C.int(input), C.int(output), C.int(size)) 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_jpeg_linux.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_jpeg.h" 4 | // #cgo LDFLAGS: -l:libjpeg.a 5 | import "C" 6 | 7 | func jpeg(input uintptr, output uintptr, size int) { 8 | C.jpeg_to_jpeg(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_png.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int png_to_png(int input, int output, int targetSize); 5 | 6 | int png_to_webp(int input, int output, int targetSize); 7 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_png_freebsd.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_png.h" 4 | // #cgo LDFLAGS: -L /usr/local/lib -L /usr/lib -L /lib -l:libsharpyuv.a -l:libpng.a -l:libz.a -l:libwebp.a -l:libpthread.a -fopenmp 5 | // #cgo CFLAGS: -I /usr/local/include 6 | import "C" 7 | 8 | func png(input uintptr, output uintptr, size int) { 9 | C.png_to_webp(C.int(input), C.int(output), C.int(size)) 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_png_linux.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_png.h" 4 | // #cgo LDFLAGS: -l:libpng.a -l:libz.a -l:libwebp.a -fopenmp 5 | import "C" 6 | 7 | func png(input uintptr, output uintptr, size int) { 8 | C.png_to_webp(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_psd.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_psd.h" 4 | // #cgo LDFLAGS: -l:libwebp.a 5 | import "C" 6 | 7 | func psd(input uintptr, output uintptr, size int) { 8 | C.psd_to_webp(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_psd.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int psd_to_webp(int input, int output, int targetSize); 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_raw.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "utils.h" 5 | #include "image_jpeg.h" 6 | 7 | int raw_to_jpeg(int inputDesc, int outputDesc, int targetSize); 8 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_raw_freebsd.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_raw.h" 4 | // #cgo LDFLAGS: -L /usr/local/lib -L /usr/lib -L /lib -l:libyuv.a -l:libjpeg.a -l:libraw.a -fopenmp -l:libc++.a -llcms2 -lm 5 | // #cgo CFLAGS: -I /usr/local/include 6 | import "C" 7 | 8 | func raw(input uintptr, output uintptr, size int) { 9 | C.raw_to_jpeg(C.int(input), C.int(output), C.int(size)) 10 | return 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_raw_linux.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_raw.h" 4 | // #cgo LDFLAGS: -l:libjpeg.a -l:libraw.a -fopenmp -l:libstdc++.a -llcms2 -lm 5 | import "C" 6 | 7 | func raw(input uintptr, output uintptr, size int) { 8 | C.raw_to_jpeg(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_webp.go: -------------------------------------------------------------------------------- 1 | package plg_image_c 2 | 3 | // #include "image_webp.h" 4 | // #cgo LDFLAGS: -l:libwebp.a 5 | import "C" 6 | 7 | func webp(input uintptr, output uintptr, size int) { 8 | C.webp_to_webp(C.int(input), C.int(output), C.int(size)) 9 | return 10 | } 11 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/image_webp.h: -------------------------------------------------------------------------------- 1 | int webp_to_webp(int inputDesc, int outputDesc, int targetSize); 2 | -------------------------------------------------------------------------------- /server/plugin/plg_image_c/utils.h: -------------------------------------------------------------------------------- 1 | #define HAS_DEBUG 0 2 | #include 3 | #if HAS_DEBUG == 1 4 | #define DEBUG(r) (fprintf(stderr, "[DEBUG::('" r "')(%.2Fms)]", ((double)clock() - t)/CLOCKS_PER_SEC * 1000)) 5 | #else 6 | #define DEBUG(r) ((void)0) 7 | #endif 8 | 9 | #define ERROR(r) (fprintf(stderr, "[ERROR:('" r "')]")) 10 | 11 | #define min(a, b) (a > b ? b : a) 12 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/deps/src/libresize.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int image_resize(const char *filename, void **buf, size_t *len, int size, int crop, int quality, int exif); 4 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/deps/src/libresize_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "libresize.h" 5 | 6 | double benchmark_image_resize(int n, const char*input); 7 | 8 | int main(int argc, char **argv) { 9 | if(argc != 2){ 10 | printf("missing argument: need a path to an image\n"); 11 | exit(1); 12 | } 13 | printf("=> benchmark %s: %.2fms\n", argv[1], benchmark_image_resize(20, argv[1])); 14 | } 15 | 16 | double benchmark_image_resize(int n, const char* input) { 17 | double total = 0; 18 | void *buffer; 19 | size_t len; 20 | 21 | int i = 0; 22 | for(i=0; i 2 | 3 | int image_transcode_compute(const char* filename, int min_width); 4 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/deps/src/libtranscode_test.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "libtranscode.h" 4 | 5 | double benchmark_image_transcode(int n, const char*input); 6 | 7 | int main(int argc, char **argv) { 8 | if(argc != 2){ 9 | printf("missing argument: need a path to an image\n"); 10 | exit(1); 11 | } 12 | printf("=> benchmark %s: %.2fms\n", argv[1], benchmark_image_transcode(20, argv[1])); 13 | } 14 | 15 | double benchmark_image_transcode(int n, const char* input) { 16 | double total = 0; 17 | int i = 0; 18 | for(i=0; i libresize_linux_amd64.a & 10 | curl -sk https://downloads.filestash.app/upload/libtranscode_Linux-x86_64.a > libtranscode_linux_amd64.a & 11 | 12 | # ARM 13 | curl -sk https://downloads.filestash.app/upload/libresize_Linux-armv7l.a > libresize_linux_arm.a & 14 | curl -sk https://downloads.filestash.app/upload/libtranscode_Linux-armv7l.a > libtranscode_linux_arm.a & 15 | 16 | wait 17 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/lib_resize_linux_amd64.go: -------------------------------------------------------------------------------- 1 | package plg_image_light 2 | 3 | // #cgo LDFLAGS: -lm -lgmodule-2.0 -lgobject-2.0 -lglib-2.0 -ldl -L./deps -l:libresize_linux_amd64.a 4 | import "C" 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/lib_resize_linux_arm.go: -------------------------------------------------------------------------------- 1 | package plg_image_light 2 | 3 | // #cgo LDFLAGS: -lm -lgmodule-2.0 -lgobject-2.0 -lglib-2.0 -ldl -L./deps -l:libresize_linux_arm.a 4 | import "C" 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/lib_transcode_linux_amd64.go: -------------------------------------------------------------------------------- 1 | package plg_image_light 2 | 3 | // #cgo LDFLAGS: -lm -lpthread -L./deps -l:libtranscode_linux_amd64.a 4 | import "C" 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_light/lib_transcode_linux_arm.go: -------------------------------------------------------------------------------- 1 | package plg_image_light 2 | 3 | // #cgo LDFLAGS: -lm -lpthread -L./deps -l:libtranscode_linux_arm.a 4 | import "C" 5 | -------------------------------------------------------------------------------- /server/plugin/plg_image_transcode/transcode_bmp.go: -------------------------------------------------------------------------------- 1 | package plg_image_transcode 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | _ "golang.org/x/image/bmp" 6 | "image" 7 | "image/jpeg" 8 | "io" 9 | ) 10 | 11 | func transcodeBmp(reader io.Reader) (io.ReadCloser, string, error) { 12 | img, _, err := image.Decode(reader) 13 | if err != nil { 14 | return nil, "", err 15 | } 16 | 17 | r, w := io.Pipe() 18 | go func() { 19 | err := jpeg.Encode(w, img, &jpeg.Options{Quality: 80}) 20 | w.Close() 21 | if err != nil { 22 | Log.Debug("plg_image_transcode::bmp jpeg encoding error '%s'", err.Error()) 23 | } 24 | }() 25 | return NewReadCloserFromReader(r), "image/jpeg", nil 26 | } 27 | -------------------------------------------------------------------------------- /server/plugin/plg_image_transcode/transcode_tiff.go: -------------------------------------------------------------------------------- 1 | package plg_image_transcode 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | _ "golang.org/x/image/tiff" 6 | "image" 7 | "image/jpeg" 8 | "io" 9 | ) 10 | 11 | func transcodeTiff(reader io.Reader) (io.ReadCloser, string, error) { 12 | img, _, err := image.Decode(reader) 13 | if err != nil { 14 | return nil, "", err 15 | } 16 | 17 | r, w := io.Pipe() 18 | go func() { 19 | err := jpeg.Encode(w, img, &jpeg.Options{Quality: 80}) 20 | w.Close() 21 | if err != nil { 22 | Log.Debug("plg_image_transcode::tiff jpeg encoding error '%s'", err.Error()) 23 | } 24 | }() 25 | return NewReadCloserFromReader(r), "image/jpeg", nil 26 | } 27 | -------------------------------------------------------------------------------- /server/plugin/plg_override_actiondelete/index.go: -------------------------------------------------------------------------------- 1 | package plg_override_actiondelete 2 | 3 | import ( 4 | "embed" 5 | 6 | . "github.com/mickael-kerjean/filestash/server/common" 7 | ) 8 | 9 | //go:embed assets/* 10 | var STATIC embed.FS 11 | 12 | func init() { 13 | Hooks.Register.StaticPatch(STATIC) 14 | } 15 | -------------------------------------------------------------------------------- /server/plugin/plg_override_download/README.md: -------------------------------------------------------------------------------- 1 | ``` 2 | git diff public/assets/pages/filespage/thing.js > server/plugin/plg_override_download/assets/pages/filespage/thing.js 3 | ``` 4 | -------------------------------------------------------------------------------- /server/plugin/plg_override_download/index.go: -------------------------------------------------------------------------------- 1 | package plg_override_download 2 | 3 | import ( 4 | "embed" 5 | 6 | . "github.com/mickael-kerjean/filestash/server/common" 7 | ) 8 | 9 | //go:embed assets/* 10 | var STATIC embed.FS 11 | 12 | func init() { 13 | Hooks.Register.StaticPatch(STATIC) 14 | } 15 | -------------------------------------------------------------------------------- /server/plugin/plg_search_example/index.go: -------------------------------------------------------------------------------- 1 | package plg_search_example 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | ) 6 | 7 | func init() { 8 | Hooks.Register.SearchEngine(ExampleSearch{}) 9 | } 10 | 11 | type ExampleSearch struct{} 12 | 13 | func (this ExampleSearch) Query(app App, path string, keyword string) ([]IFile, error) { 14 | files := []IFile{} 15 | files = append(files, File{ 16 | FName: "keyword-" + keyword + ".txt", 17 | FType: "file", // ENUM("file", "directory") 18 | FSize: 42, 19 | FPath: "/fullpath/keyword-" + keyword + ".txt", 20 | }) 21 | return files, nil 22 | } 23 | -------------------------------------------------------------------------------- /server/plugin/plg_search_sqlitefts/crawler/daemon.go: -------------------------------------------------------------------------------- 1 | package plg_search_sqlitefts 2 | 3 | import ( 4 | "time" 5 | 6 | . "github.com/mickael-kerjean/filestash/server/common" 7 | ) 8 | 9 | var onConfigChange ChangeListener 10 | 11 | func init() { 12 | onConfigChange = Config.ListenForChange() 13 | Hooks.Register.Onload(func() { 14 | for i := 0; i < SEARCH_PROCESS_PAR(); i++ { 15 | go runner() 16 | } 17 | }) 18 | } 19 | 20 | func runner() { 21 | startSearch := false 22 | for { 23 | if SEARCH_ENABLE() == false { 24 | select { 25 | case <-onConfigChange.Listener: 26 | startSearch = SEARCH_ENABLE() 27 | } 28 | if startSearch == false { 29 | continue 30 | } 31 | } 32 | crwlr := NextCrawler() 33 | if crwlr == nil { 34 | time.Sleep(5 * time.Second) 35 | continue 36 | } 37 | crwlr.mu.Lock() 38 | crwlr.Run() 39 | crwlr.mu.Unlock() 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /server/plugin/plg_search_sqlitefts/index.go: -------------------------------------------------------------------------------- 1 | package plg_search_sqlitefts 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | . "github.com/mickael-kerjean/filestash/server/plugin/plg_search_sqlitefts/crawler" 6 | ) 7 | 8 | func init() { 9 | Hooks.Register.SearchEngine(SearchEngine{}) 10 | Hooks.Register.AuthorisationMiddleware(FileHook{}) 11 | } 12 | -------------------------------------------------------------------------------- /server/plugin/plg_search_sqlitefts/indexer/error.go: -------------------------------------------------------------------------------- 1 | package indexer 2 | 3 | import ( 4 | "database/sql" 5 | "fmt" 6 | 7 | "github.com/mattn/go-sqlite3" 8 | ) 9 | 10 | var ( 11 | ErrConstraint = fmt.Errorf("DB_CONSTRAINT_FAILED_ERROR") 12 | ErrNoRows = fmt.Errorf("NO_ROWS") 13 | ) 14 | 15 | func toErr(err error) error { 16 | if sqliteErr, ok := (err).(sqlite3.Error); ok { 17 | if err == sql.ErrNoRows { 18 | return ErrNoRows 19 | } else if sqliteErr.Code == sqlite3.ErrConstraint { 20 | return ErrConstraint 21 | } 22 | } 23 | return err 24 | } 25 | -------------------------------------------------------------------------------- /server/plugin/plg_search_sqlitefts/query.go: -------------------------------------------------------------------------------- 1 | package plg_search_sqlitefts 2 | 3 | import ( 4 | . "github.com/mickael-kerjean/filestash/server/common" 5 | . "github.com/mickael-kerjean/filestash/server/plugin/plg_search_sqlitefts/crawler" 6 | ) 7 | 8 | type SearchEngine struct{} 9 | 10 | func (this SearchEngine) Query(app App, path string, keyword string) ([]IFile, error) { 11 | DaemonState.HintLs(&app, path) 12 | s := GetCrawler(&app) 13 | if s == nil { 14 | return nil, ErrNotReachable 15 | } 16 | if path == "" { 17 | path = "/" 18 | } 19 | return s.State.Search(path, keyword) 20 | } 21 | --------------------------------------------------------------------------------