Compare commits

..

194 Commits

Author SHA1 Message Date
dependabot[bot]
842921afb9 chore(deps): bump js-yaml, knip and mocha
Bumps [js-yaml](https://github.com/nodeca/js-yaml) to 4.1.1 and updates ancestor dependencies [js-yaml](https://github.com/nodeca/js-yaml), [knip](https://github.com/webpro-nl/knip/tree/HEAD/packages/knip) and [mocha](https://github.com/mochajs/mocha). These dependencies need to be updated together.


Updates `js-yaml` from 4.1.0 to 4.1.1
- [Changelog](https://github.com/nodeca/js-yaml/blob/master/CHANGELOG.md)
- [Commits](https://github.com/nodeca/js-yaml/compare/4.1.0...4.1.1)

Updates `knip` from 5.6.1 to 5.69.1
- [Release notes](https://github.com/webpro-nl/knip/releases)
- [Changelog](https://github.com/webpro-nl/knip/blob/main/packages/knip/.release-it.json)
- [Commits](https://github.com/webpro-nl/knip/commits/5.69.1/packages/knip)

Updates `mocha` from 10.4.0 to 10.8.2
- [Release notes](https://github.com/mochajs/mocha/releases)
- [Changelog](https://github.com/mochajs/mocha/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mochajs/mocha/compare/v10.4.0...v10.8.2)

---
updated-dependencies:
- dependency-name: js-yaml
  dependency-version: 4.1.1
  dependency-type: indirect
- dependency-name: knip
  dependency-version: 5.69.1
  dependency-type: direct:development
- dependency-name: mocha
  dependency-version: 10.8.2
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-15 10:40:11 +00:00
Thomas Durieux
b2d77faa6c try to fix repo access 2025-04-01 22:27:41 +02:00
dependabot[bot]
c2a423714f chore(deps): bump path-to-regexp and express (#369)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.10 to 0.1.12
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12)

Updates `express` from 4.20.0 to 4.21.2
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.20.0...4.21.2)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-01 12:59:46 -07:00
Adam Leskis
d86114fa22 fix simple typos (#384) 2025-04-01 12:59:23 -07:00
Thomas Durieux
0c0cfe2c86 Update faq.htm 2025-01-30 08:36:37 -08:00
dependabot[bot]
3602f343ac chore(deps): bump path-to-regexp and express (#324)
Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.10 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together.


Updates `path-to-regexp` from 0.1.7 to 0.1.10
- [Release notes](https://github.com/pillarjs/path-to-regexp/releases)
- [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md)
- [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.7...v0.1.10)

Updates `express` from 4.19.2 to 4.20.0
- [Release notes](https://github.com/expressjs/express/releases)
- [Changelog](https://github.com/expressjs/express/blob/master/History.md)
- [Commits](https://github.com/expressjs/express/compare/4.19.2...4.20.0)

---
updated-dependencies:
- dependency-name: path-to-regexp
  dependency-type: indirect
- dependency-name: express
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-18 17:35:05 +02:00
dependabot[bot]
f46e379b8d chore(deps): bump fast-xml-parser and @aws-sdk/client-s3 (#320)
Bumps [fast-xml-parser](https://github.com/NaturalIntelligence/fast-xml-parser) to 4.4.1 and updates ancestor dependency [@aws-sdk/client-s3](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-s3). These dependencies need to be updated together.


Updates `fast-xml-parser` from 4.2.5 to 4.4.1
- [Release notes](https://github.com/NaturalIntelligence/fast-xml-parser/releases)
- [Changelog](https://github.com/NaturalIntelligence/fast-xml-parser/blob/master/CHANGELOG.md)
- [Commits](https://github.com/NaturalIntelligence/fast-xml-parser/compare/v4.2.5...v4.4.1)

Updates `@aws-sdk/client-s3` from 3.540.0 to 3.637.0
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-s3/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.637.0/clients/client-s3)

---
updated-dependencies:
- dependency-name: fast-xml-parser
  dependency-type: indirect
- dependency-name: "@aws-sdk/client-s3"
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-18 17:34:50 +02:00
dependabot[bot]
e278381eca chore(deps): bump @grpc/grpc-js from 1.10.4 to 1.11.1 (#310)
Bumps [@grpc/grpc-js](https://github.com/grpc/grpc-node) from 1.10.4 to 1.11.1.
- [Release notes](https://github.com/grpc/grpc-node/releases)
- [Commits](https://github.com/grpc/grpc-node/compare/@grpc/grpc-js@1.10.4...@grpc/grpc-js@1.11.1)

---
updated-dependencies:
- dependency-name: "@grpc/grpc-js"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-18 17:34:35 +02:00
tdurieux
f93eb8787e fix: protect archive.finalize 2024-07-22 16:31:52 +02:00
tdurieux
d8dd408a65 fix: avoid cache of list of files 2024-07-22 16:20:18 +02:00
dependabot[bot]
27583e6a17 chore(deps-dev): bump braces from 3.0.2 to 3.0.3 (#303)
Bumps [braces](https://github.com/micromatch/braces) from 3.0.2 to 3.0.3.
- [Changelog](https://github.com/micromatch/braces/blob/master/CHANGELOG.md)
- [Commits](https://github.com/micromatch/braces/compare/3.0.2...3.0.3)

---
updated-dependencies:
- dependency-name: braces
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-17 13:26:25 +02:00
tdurieux
f81c63d2af fix: improve perf of getToken 2024-06-19 10:16:38 +02:00
tdurieux
532c094388 fix: improve token management 2024-06-18 12:00:53 +02:00
Sebastian Ramacher
9271332d5b chore: Fix typos (#292) 2024-05-28 19:11:19 +02:00
tdurieux
e9e881fdc3 fix(#290): fix tree rendering of files inside a single folder 2024-05-15 11:18:16 +02:00
tdurieux
a30d5b31a6 fix(#286): fix open and closing folder 2024-05-13 18:45:11 +02:00
tdurieux
dcf483ea03 feat: improve download anonymized repository 2024-05-06 11:52:32 +02:00
tdurieux
93606a5c39 fix: catch error when requesting a folder 2024-05-03 10:49:25 +02:00
tdurieux
ca04339529 feat: list files in folder in webview 2024-05-02 11:49:00 +01:00
tdurieux
ed11e9db36 fix: undefined in path.join 2024-05-02 11:09:20 +01:00
tdurieux
3536f78a99 fix(#283): Fix webview for web in folder 2024-04-30 11:28:32 +01:00
tdurieux
3a00a27153 feat: improve support for binary & audio files 2024-04-28 10:01:40 +01:00
tdurieux
72c8f80bce fix: fix file path in webview 2024-04-28 09:38:49 +01:00
tdurieux
17abc47d08 fix: fix webview on root repo 2024-04-28 08:08:39 +01:00
tdurieux
17cb1f294f chore: remove all reference to originalFiles 2024-04-27 18:04:51 +01:00
tdurieux
3d3a03fd04 add index on path and repoId for files 2024-04-27 17:49:13 +01:00
tdurieux
378942a28e fix: fix file list collection 2024-04-27 17:05:39 +01:00
tdurieux
2a145730b7 Improve log and GH token validation 2024-04-27 16:19:33 +01:00
tdurieux
6476899764 fix: fix webview 2024-04-26 14:01:46 +01:00
tdurieux
a86e050f8b fix: handle empty repository 2024-04-26 13:48:32 +01:00
tdurieux
8712746e93 feat: check if file list exist when checking if repo is ready 2024-04-26 13:10:09 +01:00
tdurieux
a0dff4389d fix: fix ui folder tree 2024-04-26 12:50:24 +01:00
tdurieux
b0fa5e6689 fix: hot fix, replace repoID by repoId 2024-04-26 12:40:56 +01:00
tdurieux
a9fefcc970 chore: remove console.log 2024-04-26 10:51:43 +01:00
tdurieux
710f7328e7 feat: flatten file tree for better performance 2024-04-26 10:32:09 +01:00
Joel Coffman
ccdc95e4a8 doc(#269) Document the lack of support for Jekyll
Compatibility with GitHub Pages is limited: Jekyll (and other static
site generators) are not supported. This change documents this
limitation on the home page and FAQs.

Although Markdown files are converted to HTML and thus accessible when
anonymized GitHub Pages is enabled for the repository, the Markdown to
HTML conversion includes only the content -- i.e., there is no special
formatting (as would be available when using Jekyll).

For anyone who wants to use Jekyll, a potential workaround is to build
the site locally and commit the generated site to the repository.

Closes #269

Co-authored-by: Joel Coffman <joel.coffman@acm.org>
2024-04-16 08:26:44 +01:00
tdurieux
a612b7a8b7 fix: fix queue admin 2024-04-12 10:02:23 +01:00
tdurieux
daf3276f7f fix: fix queue admin 2024-04-12 09:56:39 +01:00
tdurieux
b4ff27f560 fix: improve katex support 2024-04-11 21:38:42 +01:00
tdurieux
f65d167532 fix: use correct hostname for the streamer 2024-04-11 21:38:24 +01:00
tdurieux
03835e86ab fix: handle error in queue admin 2024-04-11 17:48:41 +01:00
tdurieux
79c6b603b4 fix: handle error in queue admin 2024-04-11 17:22:08 +01:00
tdurieux
6b9574add3 fix: improve repository rename 2024-04-11 17:13:01 +01:00
tdurieux
61c6a79949 feat: check repo status before update 2024-04-11 15:25:45 +01:00
tdurieux
05fa010349 fix: attempt at avoiding double save 2024-04-11 15:12:34 +01:00
tdurieux
389030adc9 refactor: rely more on the db instead of querying GH 2024-04-06 15:15:08 +01:00
tdurieux
968a59726c feat: increase caching when file version is provided 2024-04-06 10:05:07 +01:00
tdurieux
593dbed822 fix: attempt at avoiding double save 2024-04-06 09:33:10 +01:00
tdurieux
ae4cb9e898 fix: fix typo in deploy 2024-04-05 14:49:24 +01:00
tdurieux
80101f83aa fix: fix dns lookup for dnsrr 2024-04-05 14:48:40 +01:00
tdurieux
de56021e48 fix: fix cache folder configuration 2024-04-05 13:14:46 +01:00
tdurieux
9048b5c3b1 fix: fix healthcheck 2024-04-05 13:11:43 +01:00
tdurieux
c940c98b6e fix: add missing gulpfile.js 2024-04-05 12:30:47 +01:00
tdurieux
11a6c06d11 feat: add donation button on status page 2024-04-05 12:25:20 +01:00
tdurieux
27c54b0182 feat: add link to website if enabled 2024-04-05 12:10:07 +01:00
tdurieux
cb3d999ed3 fix: add missing KaTeX fonts 2024-04-05 12:02:50 +01:00
tdurieux
f30110c567 fix: improve link rendering 2024-04-05 11:04:29 +01:00
tdurieux
c3a890dac7 fix: fix minimization of the client js 2024-04-05 10:34:24 +01:00
tdurieux
9e995a04db fix: fix code rendering 2024-04-05 10:21:38 +01:00
tdurieux
7ed973ccfc fix: fix code rendering 2024-04-05 10:17:47 +01:00
tdurieux
22a28a913d perf: improve page loading time 2024-04-05 01:02:41 +01:00
tdurieux
8fdd6228e4 fix(#251): fix notebook and code dark mode 2024-04-04 18:35:01 +01:00
tdurieux
f5ec343a9c fix(#263): render math expression correctly 2024-04-04 18:08:03 +01:00
tdurieux
f5d45394bf feat: add sha to file path to avoid caching 2024-04-04 15:56:38 +01:00
tdurieux
3cbf78beb8 fix: fix execution order in removeCache 2024-04-04 08:44:59 +01:00
tdurieux
ca3996775b chore: cleanup console 2024-04-03 20:38:48 +01:00
tdurieux
42c3a58a46 feat: add edit button on repo view 2024-04-03 19:11:10 +01:00
tdurieux
6e8d006220 fix: fix filePath when anonymized 2024-04-03 18:57:52 +01:00
tdurieux
795a67cdb2 fix: fix anonymization client script 2024-04-03 18:41:00 +01:00
tdurieux
1d4bab7866 fix: fix webview & improve download progress 2024-04-03 18:25:33 +01:00
tdurieux
83c55fdfbf fix: typo 2024-04-03 13:27:05 +01:00
tdurieux
db67f53b2c fix: fix GitHubDownload 2024-04-03 13:24:34 +01:00
tdurieux
fc469be61b fix: fix queue 2024-04-03 11:47:32 +01:00
tdurieux
4d12641c7e feat: introduce streamers that handle the stream and anonymization from github 2024-04-03 11:13:01 +01:00
tdurieux
73019c1b44 fix: fix gh repository configuration 2024-04-02 14:46:45 +01:00
tdurieux
fa2591fe38 refactor: uncouple repository class & token 2024-04-02 13:51:13 +01:00
tdurieux
ea96c31e9d fix: fix github authentification 2024-04-02 09:10:14 +01:00
tdurieux
8a9d2d8395 fix: add missing await 2024-04-01 16:03:31 +01:00
tdurieux
4881719160 fix: add missing await 2024-04-01 15:36:16 +01:00
tdurieux
35f4b4ce52 refactor: improve file streaming 2024-04-01 15:17:26 +01:00
tdurieux
87c7e8c470 chore: update node version 2024-04-01 10:27:18 +01:00
tdurieux
a34ff741ab fix: fix profil url 2024-04-01 09:20:20 +01:00
tdurieux
07d8dd9130 feat: cache server stat 2024-04-01 09:19:49 +01:00
tdurieux
a8f361f25f fix: add missing file 2024-04-01 06:58:00 +01:00
tdurieux
d2aa5d6361 refactor: use replicas instead of node forks 2024-04-01 06:43:51 +01:00
tdurieux
d3924698f6 improve performance 2024-03-31 15:12:46 +01:00
tdurieux
bee5c5834c fix: add missing package 2024-03-31 14:33:22 +01:00
tdurieux
d3017a771d improve performance 2024-03-31 14:23:53 +01:00
tdurieux
3323d2d0c0 fix: never return the complete file list 2024-03-31 12:51:54 +01:00
tdurieux
e1ef44bd6d fix: fix jaeger port 2024-03-28 10:14:14 +00:00
tdurieux
8505daceaa chore: remove pm2 install 2024-03-28 10:14:00 +00:00
tdurieux
829720b131 chore: update dependencies 2024-03-27 11:45:41 +00:00
tdurieux
0caf786c9c feat: adds opentelemetry support 2024-03-27 11:18:13 +00:00
dependabot[bot]
803720e2ea chore(deps): bump ip from 2.0.0 to 2.0.1 (#258)
Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1.
- [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: ip
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-02-20 22:53:59 +00:00
tdurieux
fa189949a6 fix: protect file list download 2024-01-12 15:33:18 +01:00
tdurieux
b103370d2b fix: protect file list download 2024-01-12 15:31:09 +01:00
tdurieux
9a48aa1fa2 fix: protect file list download 2024-01-12 15:11:46 +01:00
dependabot[bot]
c2a885fdaa chore(deps): bump msgpackr from 1.9.7 to 1.10.1 (#250)
Bumps [msgpackr](https://github.com/kriszyp/msgpackr) from 1.9.7 to 1.10.1.
- [Release notes](https://github.com/kriszyp/msgpackr/releases)
- [Commits](https://github.com/kriszyp/msgpackr/compare/v1.9.7...v1.10.1)

---
updated-dependencies:
- dependency-name: msgpackr
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-29 11:36:30 +01:00
tdurieux
5be67a44cf fix: update status when updating PRs 2023-11-15 10:02:45 +01:00
tdurieux
995d5705db fix: update status when updating PRs 2023-11-15 09:48:21 +01:00
tdurieux
e553561ccb refactor: replace repository status by its enum 2023-08-31 11:32:51 +02:00
dependabot[bot]
1671a16025 chore(deps): bump mongodb and mongoose (#236)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) to 5.8.1 and updates ancestor dependency [mongoose](https://github.com/Automattic/mongoose). These dependencies need to be updated together.


Updates `mongodb` from 5.7.0 to 5.8.1
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/v5.8.1/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v5.7.0...v5.8.1)

Updates `mongoose` from 7.4.5 to 7.5.0
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.4.5...7.5.0)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: indirect
- dependency-name: mongoose
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-31 10:32:01 +02:00
tdurieux
e7d4af387a fix: fix slowDown when used behind cloudflare 2023-08-28 15:39:41 +02:00
tdurieux
4b20a96c96 fix: rate limit 2023-08-28 15:35:16 +02:00
tdurieux
42b885d5a1 fix(#234): fix FAQ related to supported file types 2023-08-28 15:12:26 +02:00
tdurieux
696a465d5c 2.2.0 2023-08-28 14:46:54 +02:00
tdurieux
ecfd69bd37 fix: fix zip extract 2023-08-28 14:36:04 +02:00
tdurieux
d8de3f189a Release 2.1.5 2023-08-28 12:12:16 +02:00
tdurieux
f72a662750 chore: update dependencies 2023-08-28 12:12:13 +02:00
tdurieux
2f5d7a1089 fix: improve S3 reliability 2023-08-28 12:11:43 +02:00
tdurieux
92347fbcfb fix: trust proxy parameter 2023-08-28 12:11:43 +02:00
dependabot[bot]
48ae137f96 chore(deps): bump semver from 5.7.1 to 5.7.2 (#224)
Bumps [semver](https://github.com/npm/node-semver) from 5.7.1 to 5.7.2.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v5.7.2/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v5.7.1...v5.7.2)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-08-14 23:11:40 +02:00
tdurieux
84877506a6 fix: fix comments URL API 2023-07-25 12:47:21 +02:00
dependabot[bot]
275d4827a8 chore(deps): bump mongoose from 7.3.1 to 7.3.3 (#226)
Bumps [mongoose](https://github.com/Automattic/mongoose) from 7.3.1 to 7.3.3.
- [Release notes](https://github.com/Automattic/mongoose/releases)
- [Changelog](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md)
- [Commits](https://github.com/Automattic/mongoose/compare/7.3.1...7.3.3)

---
updated-dependencies:
- dependency-name: mongoose
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-18 22:27:07 +02:00
tdurieux
9fea119f50 chore: improve job status reporting 2023-07-05 13:43:57 +02:00
tdurieux
68d96ad82e chore: update dependencies 2023-06-26 18:24:28 +02:00
tdurieux
f54b9f355b fix: make the repoId case insensitive 2023-06-26 18:17:49 +02:00
tdurieux
e24d1b4630 update dependencies & remove google analytics 2023-06-20 09:58:25 +02:00
tdurieux
406330d957 improve error handling during the download process 2023-05-31 11:46:20 +02:00
tdurieux
0997e19d3d fix(#208) update notebook renderer for the last version of marked 2023-05-16 14:34:01 +02:00
tdurieux
897426743f force GitHubStream when updating a repository 2023-05-10 08:05:52 +02:00
tdurieux
2f916c6968 fix: auto select file when a folder is selected 2023-05-08 15:39:17 +02:00
tdurieux
027f14ffbc fix: improve error message for folders 2023-05-08 15:16:56 +02:00
tdurieux
4f6c1d25fc fix: always send a response 2023-05-08 14:14:19 +02:00
tdurieux
6c4363182b chore: update decompress-stream-to-s3 2023-05-08 13:57:16 +02:00
tdurieux
66d5d91e3e fix(#206): make sure that all text files are anonimized 2023-05-08 13:56:33 +02:00
tdurieux
deba2b567e fix: change deprecated property for S3 timeout 2023-05-03 08:34:14 +02:00
tdurieux
e5ffad6364 fix(#205): fix encoded urls 2023-05-02 18:31:57 +02:00
tdurieux
f1d6e4534d change default filter for the admin 2023-05-02 18:22:14 +02:00
tdurieux
dde7fa2d72 feat(#204): display videos in md 2023-05-02 18:21:47 +02:00
tdurieux
abddf10c11 fix: fix anonymization of raw links 2023-05-02 16:00:47 +02:00
tdurieux
53ea31008a fix: download the repository if the file is cached 2023-05-02 08:17:46 +02:00
tdurieux
7d8b087a5d fix: improve reqs on non-existing files 2023-05-01 22:45:18 +02:00
tdurieux
a23f089a8a fix: hotfix for config 2023-05-01 14:54:47 +02:00
tdurieux
ee82d3c12a chore: update dependencies and update AWS S3 lib to v3 2023-05-01 14:53:27 +02:00
tdurieux
6226f32471 fix(#203): recursively get all files for downloaded repositories 2023-05-01 09:47:36 +02:00
tdurieux
3bf6864472 feat: improve error management in front end 2023-04-26 00:27:52 +02:00
tdurieux
083026f168 fix: fix content type for typescript 2023-04-26 00:21:49 +02:00
tdurieux
35d796f871 fix: fix content type for typescript 2023-04-26 00:19:26 +02:00
tdurieux
7e2c490e4b feat(#200): save the commit date of the anonymized commit 2023-04-25 23:40:12 +02:00
tdurieux
c9acb7b899 feat: improve response content type header 2023-04-25 17:42:50 +02:00
tdurieux
8ac3a66a30 feat(#169): add emoji support for markdown 2023-04-21 13:23:34 +02:00
tdurieux
3627096e63 feat(#148): add support for Math expression 2023-04-21 12:29:19 +02:00
tdurieux
4293fa01b2 feat: add media player in content view 2023-04-20 23:30:26 +02:00
tdurieux
13e5e35d46 fix(#199): stop content download when request is canceled and always define contentLength 2023-04-20 23:21:39 +02:00
tdurieux
0a021d6e61 fix: fix authentification for PR download 2023-04-20 13:44:35 +02:00
dependabot[bot]
a07c8d4635 chore(deps): bump xml2js from 0.4.19 to 0.5.0 (#196)
Bumps [xml2js](https://github.com/Leonidas-from-XIV/node-xml2js) from 0.4.19 to 0.5.0.
- [Release notes](https://github.com/Leonidas-from-XIV/node-xml2js/releases)
- [Commits](https://github.com/Leonidas-from-XIV/node-xml2js/compare/0.4.19...0.5.0)

---
updated-dependencies:
- dependency-name: xml2js
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-04-12 10:21:11 +02:00
tdurieux
66341ec410 fix: PR credentials 2023-04-11 09:25:29 +02:00
tdurieux
5d1eb333cf try to resolve unassessible website 2023-04-06 18:25:03 +02:00
tdurieux
9ecfdae9d7 fix: protect against double save 2023-04-06 13:36:36 +02:00
tdurieux
0afcb9733a reenable Github download 2023-04-06 13:17:07 +02:00
tdurieux
3a55a4d5b0 fix: remove quote from sha 2023-04-06 13:09:15 +02:00
tdurieux
e94a5f164a disable download mode for the moment 2023-04-05 12:12:57 +02:00
tdurieux
d29d4281ab fix: fix getUser in rate limit 2023-04-03 11:18:15 +02:00
tdurieux
f8a0315a1d feat: adapt the rate limit to the user 2023-04-03 11:11:08 +02:00
tdurieux
ed0dd82cfb fix: improve error message when too many requests are sent 2023-04-03 10:50:55 +02:00
tdurieux
d3f9e67c62 fix: try to handle duplicate user id error 2023-04-03 10:34:28 +02:00
tdurieux
344ecf2a33 feat: add a flag to know if a repo has been reseted 2023-04-03 10:21:56 +02:00
tdurieux
ef1a2bfa4a feat: check repository size when repo is updated 2023-04-03 10:10:43 +02:00
tdurieux
f1fe8eff14 feat(#171): supports display raw content 2023-03-29 13:05:13 +02:00
tdurieux
38d3e54d0b fix(#186): use a different name for the hostname configuration 2023-03-02 16:40:38 +01:00
tdurieux
74aacd223d fix(#186): use a different name for the hostname configuration 2023-03-02 16:39:01 +01:00
tdurieux
8221b2ee7f feat: dont download notebook if not necessary 2023-02-23 16:21:08 +01:00
tdurieux
c59e202124 feat: list gh repos in user admin 2023-02-22 11:05:37 +01:00
tdurieux
d825cc1d69 fix: fix admin filtering 2023-02-22 10:00:18 +01:00
tdurieux
f3b8860838 fix: fix error message when repository is not found 2023-02-22 09:57:49 +01:00
tdurieux
a558a6c2bd feat: add log in reset state 2023-02-22 09:44:35 +01:00
tdurieux
7422a3a262 fix: save model after the state reset 2023-02-22 09:41:28 +01:00
tdurieux
3c18884de2 fix: fix filter remove button in dashboard 2023-02-22 09:28:27 +01:00
tdurieux
1d4eb7a1b0 fix: fix action menu in the admin 2023-02-22 09:21:14 +01:00
tdurieux
b6049c4ed2 feat: improve the error handling in s3 2023-02-22 08:39:23 +01:00
tdurieux
7dbfdb3056 fix(#181): check if folder exists in S3 2023-02-22 08:00:33 +01:00
Maxim Van de Wynckel
6caca33145 fix(#174): correctly append trailing slash in windows
Windows requires a backslash instead of a forward slash. As this variable is used in a simple string replace, this needs to be platform specific.
2023-02-22 07:44:47 +01:00
tdurieux
8c8f8dbd90 fix: fix user connection 2023-02-16 08:27:03 +01:00
tdurieux
83a9505a11 fix: fix compilation 2023-02-16 08:21:10 +01:00
tdurieux
74d625d6d4 fix: make sure that the user data are uptodate 2023-02-16 08:18:23 +01:00
tdurieux
2b10b10207 fix: check if cache exists before removing it 2023-02-16 08:15:21 +01:00
tdurieux
2a5f22a483 fix: fix new user when it already exists 2023-02-16 08:09:49 +01:00
tdurieux
9cde774273 fix: improve error handling when users conntect 2023-02-16 07:56:50 +01:00
tdurieux
95354292b5 refactor: refactor the queue init function 2023-02-15 20:19:26 +01:00
tdurieux
da194d9d71 fix(#174) improve cli interface to anonimize repositories 2023-02-15 19:23:45 +01:00
tdurieux
fb9bbe105a fix: improve getToken 2023-02-15 19:22:11 +01:00
tdurieux
99f837c3cf fix: fix and optimize Dockerfile 2023-02-13 14:07:57 +01:00
tdurieux
ec6098b3a1 chore: use strict compilation mode 2023-02-13 13:38:57 +01:00
tdurieux
3ab9b0c7a4 fix(#166): fix docker build 2023-02-13 08:15:55 +01:00
tdurieux
cff3636523 remove log 2023-02-08 16:33:06 +01:00
tdurieux
32d1884450 fix: get files for new repos 2023-02-08 16:26:46 +01:00
tdurieux
5c72f54db5 perf: improve the perf of Anonymous GitHub 2023-02-08 15:34:50 +01:00
tdurieux
2e36b72a7f perf: improve the perf of Anonymous GitHub 2023-02-08 09:49:24 +01:00
tdurieux
73f7582fd2 feat: admin to remove repo cache 2023-02-07 13:27:06 +01:00
tdurieux
3eee62d6ad feat: increase slowdown threshold for webview 2023-02-07 09:52:19 +01:00
Thomas Durieux
696b24a648 Update README.md 2023-02-07 09:35:09 +01:00
tdurieux
7c5fcfe069 chore: improve readme 2023-02-07 09:33:42 +01:00
tdurieux
6debb6aa0f fix: do not change repoID 2023-02-07 09:10:15 +01:00
185 changed files with 27812 additions and 7869 deletions

View File

@@ -1,3 +1,5 @@
/repositories
repo/
db_backups
db_backups
build
node_modules
.github

View File

@@ -1,22 +1,21 @@
FROM node:15-slim
FROM node:21-slim
ENV PORT 5000
EXPOSE $PORT
WORKDIR /app
RUN npm install pm2 -g
RUN pm2 install typescript
COPY package.json .
COPY package-lock.json .
RUN npm install
COPY ecosystem.config.js .
COPY gulpfile.js .
COPY tsconfig.json .
COPY healthcheck.js .
COPY src .
COPY index.ts .
COPY public .
CMD [ "pm2-runtime", "ecosystem.config.js"]
COPY public ./public
COPY src ./src
RUN npm install && npm run build && npm cache clean --force
COPY opentelemetry.js .
CMD [ "node", "--require", "./opentelemetry.js", "./build/server/index.js"]

View File

@@ -1,46 +1,23 @@
# Anonymous Github
Anonymous Github is a system to anonymize Github repositories before referring to them in a double-anonymous paper submission.
To start using Anonymous Github right now: **[http://anonymous.4open.science/](http://anonymous.4open.science/)**
Anonymous Github is a system that helps anonymize Github repositories for double-anonymous paper submissions. A public instance of Anonymous Github is hosted at https://anonymous.4open.science/.
Indeed, in a double-anonymous review process, the open-science data or code that is in the online appendix must be anonymized, similarly to paper anonymization. The authors must
![screenshot](https://user-images.githubusercontent.com/5577568/217193282-42f608d3-2b46-4ebc-90df-772f248605be.png)
- anonymize URLs: the name of the institution/department/group/authors should not appear in the URLs of the open-science appendix
- anonymize the appendix content itself
Anonymizing an open-science appendix needs some work, but fortunately, this can be automated, this is what Anonymous Github is about.
Anonymous Github anonymizes the following:
Anonymous Github anonymizes:
- Github repository owner, organization, and name
- File and directory names
- File contents of all extensions, including markdown, text, Java, etc.
- the Github owner / organization / repository name
- the content of the repository
- file contents (all extensions, md/txt/java/etc)
- file and directory names
## Usage
Question / Feedback / Bug report: please open an issue in this repository.
### Public instance
## Using Anonymous Github
**https://anonymous.4open.science/**
## How to create a new anonymized repository
To use it, open the main page (e.g., [http://anonymous.4open.science/](http://anonymous.4open.science/)), login with GitHub, and click on "Anonymize".
Simply fill 1. the Github repo URL and 2. the id of the anonymized repository, 3. the terms to anonymize (which can be updated afterward).
The anonymization of the content is done by replacing all occurrences of words in a list by "XXXX" (can be changed in the configuration).
The word list is provided by the authors, and typically contains the institution name, author names, logins, etc...
The README is anonymized as well as all files of the repository. Even filenames are anonymized.
In a paper under double-anonymous review, instead of putting a link to Github, one puts a link to the Anonymous Github instance (e.g.
<http://anonymous.4open.science/r/840c8c57-3c32-451e-bf12-0e20be300389/> which is an anonymous version of this repo).
To start using Anonymous Github right now, a public instance of anonymous_github is hosted at 4open.science:
**[http://anonymous.4open.science/](http://anonymous.4open.science/)**
## What is the scope of anonymization?
In double-anonymous peer-review, the boundary of anonymization is the paper plus its online appendix, and only this, it's not the whole world. Googling any part of the paper or the online appendix can be considered as a deliberate attempt to break anonymity ([explanation](http://www.monperrus.net/martin/open-science-double-anonymous))
## CLI
### CLI
This CLI tool allows you to anonymize your GitHub repositories locally, generating an anonymized zip file based on your configuration settings.
@@ -51,13 +28,10 @@ npm install -g @tdurieux/anonymous_github
# Run the Anonymous GitHub CLI tool
anonymous_github
```
## How does it work?
Anonymous Github either download the complete repository and anonymize the content of the file or proxy the request to GitHub. In both case, the original and anonymized versions of the file are cached on the server.
### Own instance
## Installing Anonymous Github
1. Clone the repository
#### 1. Clone the repository
```bash
git clone https://github.com/tdurieux/anonymous_github/
@@ -65,9 +39,9 @@ cd anonymous_github
npm i
```
2. Configure the Github token
#### 2. Configure the GitHub token
Create a file `.env` that contains
Create a `.env` file with the following contents:
```env
GITHUB_TOKEN=<GITHUB_TOKEN>
@@ -79,19 +53,27 @@ DB_PASSWORD=
AUTH_CALLBACK=http://localhost:5000/github/auth,
```
`GITHUB_TOKEN` can be generated here: https://github.com/settings/tokens/new with `repo` scope.
`CLIENT_ID` and `CLIENT_SECRET` are the tokens are generated when you create a new GitHub app https://github.com/settings/applications/new.
The callback of the GitHub app needs to be defined as `https://<host>/github/auth` (the same as defined in AUTH_CALLBACK).
- `GITHUB_TOKEN` can be generated here: https://github.com/settings/tokens/new with `repo` scope.
- `CLIENT_ID` and `CLIENT_SECRET` are the tokens are generated when you create a new GitHub app https://github.com/settings/applications/new.
- The callback of the GitHub app needs to be defined as `https://<host>/github/auth` (the same as defined in AUTH_CALLBACK).
3. Run Anonymous Github
#### 3. Start Anonymous Github server
```bash
docker-compose up -d
```
4. Go to Anonymous Github
#### 4. Go to Anonymous Github
By default, Anonymous Github uses port 5000. It can be changed in `docker-compose.yml`.
Go to http://localhost:5000. By default, Anonymous Github uses port 5000. It can be changed in `docker-compose.yml`. I would recommand to put Anonymous GitHub behind ngnix to handle the https certificates.
## What is the scope of anonymization?
In double-anonymous peer-review, the boundary of anonymization is the paper plus its online appendix, and only this, it's not the whole world. Googling any part of the paper or the online appendix can be considered as a deliberate attempt to break anonymity ([explanation](https://www.monperrus.net/martin/open-science-double-blind))
## How does it work?
Anonymous Github either downloads the complete repository and anonymizes the content of the file or proxies the request to GitHub. In both cases, the original and anonymized versions of the file are cached on the server.
## Related tools
@@ -102,3 +84,4 @@ By default, Anonymous Github uses port 5000. It can be changed in `docker-compos
## See also
- [Open-science and double-anonymous Peer-Review](https://www.monperrus.net/martin/open-science-double-blind)
- [ACM Policy on Double-Blind Reviewing](https://dl.acm.org/journal/tods/DoubleBlindPolicy)

View File

@@ -1,19 +1,21 @@
version: "3"
version: "3.8"
services:
anonymous_github:
build: .
restart: always
image: tdurieux/anonymous_github:v2
ports:
- $EXPOSED_PORT:5000
env_file:
- ./.env
environment:
volumes:
- ./repositories:/app/repositories/
environment:
- PORT=5000
- REDIS_HOSTNAME=redis
- DB_HOSTNAME=mongodb
volumes:
- .:/app
ports:
- $PORT:$PORT
- STREAMER_ENTRYPOINT=http://streamer:5000/
healthcheck:
test:
- CMD
@@ -22,45 +24,108 @@ services:
interval: 10s
timeout: 10s
retries: 5
links:
depends_on:
- mongodb
- redis
- streamer
streamer:
build: .
restart: always
image: tdurieux/anonymous_github:v2
deploy:
mode: replicated
replicas: 4
endpoint_mode: dnsrr
entrypoint: ["node", "--require", "./opentelemetry.js", "./build/streamer/index.js"]
env_file:
- ./.env
volumes:
- ./repositories:/app/repositories/
environment:
- PORT=5000
- SERVICE_NAME=Streamer
healthcheck:
test:
- CMD
- node
- healthcheck.js
interval: 10s
timeout: 10s
retries: 5
redis:
image: "redis:alpine"
restart: always
ports:
- 127.0.0.1:6379:6379
healthcheck:
test:
- CMD
- redis-cli
- ping
interval: 10s
timeout: 10s
retries: 5
mongodb:
image: mongo:latest
restart: on-failure
ports:
- "127.0.0.1:27017:27017"
environment:
MONGO_INITDB_ROOT_USERNAME: $DB_USERNAME
MONGO_INITDB_ROOT_PASSWORD: $DB_PASSWORD
volumes:
- mongodb_data_container:/data/db
ports:
- 127.0.0.1:27017:27017
command: --quiet
healthcheck:
test:
- CMD
- mongo
- mongosh
- --eval
- "db.adminCommand('ping')"
interval: 10s
timeout: 10s
retries: 5
opentelemetry:
image: otel/opentelemetry-collector
restart: always
command: ["--config=/etc/otel-collector-config.yaml"]
volumes:
- ./opentelemetry-collector.yml:/etc/otel-collector-config.yaml
depends_on:
- jaeger
- prometheus
jaeger:
image: jaegertracing/all-in-one:latest
restart: always
ports:
- 127.0.0.1:16686:16686
prometheus:
image: prom/prometheus:latest
restart: always
volumes:
- ./prometheus.yaml:/etc/prometheus/prometheus.yml
ports:
- 127.0.0.1:9090:9090
mongodb-backup:
image: tiredofit/db-backup
links:
- mongodb
env_file:
- ./.env
volumes:
- ./db_backups:/backup
environment:
- DB_TYPE=mongo
- DB_HOST=mongodb
- DB_DUMP_FREQ=60
- DB_CLEANUP_TIME=240
- DB_DUMP_FREQ=120
- DB_CLEANUP_TIME=500
- COMPRESSION=XZ
- DB_USER=$DB_USERNAME
- DB_PASS=$DB_PASSWORD

View File

@@ -1,21 +0,0 @@
module.exports = {
apps: [
{
name: "AnonymousGitHub",
script: "./index.ts",
exec_mode: "fork",
watch: true,
ignore_watch: [
"node_modules",
"repositories",
"repo",
"public",
".git",
"db_backups",
"dist",
],
interpreter: "node",
interpreter_args: "--require ts-node/register",
},
],
};

59
gulpfile.js Normal file
View File

@@ -0,0 +1,59 @@
const { src, dest } = require("gulp");
const uglify = require("gulp-uglify");
const concat = require("gulp-concat");
var order = require("gulp-order");
const cleanCss = require("gulp-clean-css");
function defaultTask(cb) {
const jsFiles = [
"public/script/external/angular.min.js",
"public/script/external/angular-translate.min.js",
"public/script/external/angular-translate-loader-static-files.min.js",
"public/script/external/angular-sanitize.min.js",
"public/script/external/angular-route.min.js",
"public/script/external/pdf.compat.js",
"public/script/external/pdf.js",
"public/script/external/github-emojis.js",
"public/script/external/marked-emoji.js",
"public/script/external/marked.min.js",
"public/script/external/purify.min.js",
"public/script/external/ansi_up.min.js",
"public/script/external/prism.min.js",
"public/script/external/katex.min.js",
"public/script/external/katex-auto-render.min.js",
"public/script/external/marked-katex-extension.umd.min.js",
"public/script/external/notebook.min.js",
"public/script/external/org.js",
"public/script/external/jquery-3.4.1.min.js",
"public/script/external/popper.min.js",
"public/script/external/bootstrap.min.js",
"public/script/external/ace/ace.js",
"public/script/external/ui-ace.min.js",
"public/script/utils.js",
"public/script/ng-pdfviewer.min.js",
"public/script/app.js",
"public/script/admin.js",
];
const cssFiles = [
"public/css/bootstrap.min.css",
"public/css/font-awesome.min.css",
"public/css/notebook.css",
"public/css/katex.min.css",
"public/css/github-markdown.min.css",
"public/css/style.css",
];
src(jsFiles)
.pipe(order(jsFiles, { base: "./" }))
.pipe(concat("bundle.min.js"))
.pipe(uglify())
.pipe(dest("public/script"))
.on("end", cb);
src(cssFiles)
.pipe(order(cssFiles, { base: "./" }))
.pipe(concat("all.min.css"))
.pipe(cleanCss())
.pipe(dest("public/css"));
}
exports.default = defaultTask;

View File

@@ -1,22 +1,26 @@
require("dotenv").config();
const http = require("http");
const config = require("./config");
const config = require("./build/config");
const options = {
host: "localhost",
port: config.PORT,
path: "/healthcheck",
method: "GET",
host: "127.0.0.1",
port: config.default.PORT,
timeout: 2000,
};
const request = http.request(options, (res) => {
if (res.statusCode == 200) {
if (res.statusCode == 200 || res.statusCode == 404) {
process.exit(0);
} else {
const reqURL = `${res.req.protocol}://${res.req.host}:${options.port}${res.req.path}`;
console.log(reqURL, res.statusCode);
process.exit(1);
}
});
request.on("error", (err) => {
console.log("ERROR");
console.log("ERROR", err);
process.exit(1);
});

153
import.js
View File

@@ -1,153 +0,0 @@
const fs = require("fs").promises;
const ofs = require("fs");
const path = require("path");
const gh = require("parse-github-url");
const { Octokit } = require("@octokit/rest");
const config = require("./config");
const db = require("./utils/database");
const repoUtils = require("./utils/repository");
const fileUtils = require("./utils/file");
const githubUtils = require("./utils/github");
// const ROOT = "./repositories";
const ROOT = "./repo";
(async () => {
await db.connect();
const repositories = await fs.readdir(ROOT);
let index = 0;
for (let repo of repositories) {
// for (let repo of ["14bfc5c6-b794-487e-a58a-c54103a93c7b"]) {
console.log("Import ", index++, "/", repositories.length, " ", repo);
try {
const conf = await repoUtils.getConfig(repo);
if (conf) {
continue;
}
// const repoPath = path.join("./repositories", repo);
const repoPath = path.join(ROOT, repo);
const configPath = path.join(repoPath, "config.json");
if (!ofs.existsSync(configPath)) {
continue;
}
const repoConfig = JSON.parse(await fs.readFile(configPath));
const r = gh(repoConfig.repository);
if (r == null) {
console.log(`${repoConfig.repository} is not a valid github url.`);
continue;
}
const fullName = `${r.owner}/${r.name}`;
// const octokit = new Octokit({ auth: config.GITHUB_TOKEN });
// try {
// await octokit.apps.checkToken({
// client_id: config.CLIENT_ID,
// access_token: repoConfig.token,
// });
// } catch (error) {
// delete repoConfig.token;
// continue
// }
let token = repoConfig.token;
if (!token) {
token = config.GITHUB_TOKEN;
}
const branches = await repoUtils.getRepoBranches({
fullName,
token,
});
const details = await repoUtils.getRepoDetails({
fullName,
token,
});
let branch = details.default_branch;
if (r.branch && branches[r.branch]) {
branch = r.branch;
}
if (!branches[branch]) {
console.log(branch, details.default_branch, branches);
}
let commit = branches[branch].commit.sha;
const anonymizeDate = new Date();
let mode = "stream";
// if (details.size < 1024) {
// mode = "download";
// }
let expirationDate = null;
if (repoConfig.expiration_date) {
expirationDate = new Date(repoConfig.expiration_date["$date"]);
}
const expirationMode = repoConfig.expiration
? repoConfig.expiration
: "never";
const repoConfiguration = {
repoId: repo,
fullName,
// owner: "tdurieux",
owner: r.owner,
terms: repoConfig.terms,
repository: repoConfig.repository,
token: repoConfig.token,
branch,
commit,
anonymizeDate,
options: {
image: false,
mode,
expirationMode,
expirationDate,
update: true,
page: details.has_pages,
pdf: false,
notebook: true,
loc: false,
link: true,
},
};
await db.get("anonymized_repositories").updateOne(
{
repoId: repo,
},
{
$set: repoConfiguration,
},
{ upsert: true }
);
if (ofs.existsSync(repoUtils.getOriginalPath(repo))) {
await fs.rm(repoUtils.getOriginalPath(repo), {
recursive: true,
force: true,
});
}
if (ofs.existsSync(repoUtils.getAnonymizedPath(repo))) {
await fs.rm(repoUtils.getAnonymizedPath(repo), {
recursive: true,
force: true,
});
}
// await githubUtils.downloadRepoAndAnonymize(repoConfiguration);
// await fileUtils.getFileList({ repoConfig: repoConfiguration });
await repoUtils.updateStatus(repoConfiguration, "ready");
console.log(
expirationDate,
expirationDate != null && expirationDate < new Date(),
expirationDate < new Date()
);
if (
expirationMode != "never" &&
expirationDate != null &&
expirationDate < new Date()
) {
await repoUtils.updateStatus(repoConfiguration, "expired");
}
} catch (error) {
console.error(error);
}
}
await db.close();
})();

View File

@@ -1,7 +0,0 @@
import { config } from "dotenv";
config();
import server from "./src/server";
// start the server
server();

View File

@@ -1,217 +0,0 @@
require("dotenv").config();
import * as mongoose from "mongoose";
import config from "./config";
import * as database from "./src/database/database";
import RepositoryModel from "./src/database/repositories/repositories.model";
import AnonymizedRepositoryModel from "./src/database/anonymizedRepositories/anonymizedRepositories.model";
import UserModel from "./src/database/users/users.model";
const MONGO_URL = `mongodb://${config.DB_USERNAME}:${config.DB_PASSWORD}@${config.DB_HOSTNAME}:27017/`;
async function connect(db) {
const t = new mongoose.Mongoose();
t.set("useNewUrlParser", true);
t.set("useFindAndModify", true);
t.set("useUnifiedTopology", true);
const database = t.connection;
await t.connect(MONGO_URL + db, {
authSource: "admin",
useCreateIndex: true,
useFindAndModify: true,
});
return database;
}
(async () => {
await database.connect();
const oldDB = await connect("anonymous_github");
console.log("Import Users");
let index = 0;
const userQuery = oldDB.collection("users").find();
const totalUser = await userQuery.count();
while (await userQuery.hasNext()) {
const r = await userQuery.next();
index++;
console.log(`Import User [${index}/${totalUser}]: ${r.username}`);
const newRepos = [];
const allRepoIds = [];
if (r.repositories) {
const finds = await RepositoryModel.find({
externalId: {
$in: r.repositories.map((repo) => "gh_" + repo.id),
},
}).select("externalId");
finds.forEach((f) => allRepoIds.push(f.id));
const repoIds = new Set<string>();
const toInsert = r.repositories.filter((f) => {
if (repoIds.has(f.id)) return false;
repoIds.add(f.id);
const externalId = "gh_" + f.id;
return finds.filter((f) => f.externalId == externalId).length == 0;
});
for (const repo of toInsert) {
newRepos.push(
new RepositoryModel({
externalId: "gh_" + repo.id,
name: repo.full_name,
url: repo.html_url,
size: repo.size,
defaultBranch: repo.default_branch,
})
);
}
if (newRepos.length > 0) {
await RepositoryModel.insertMany(newRepos);
}
newRepos.forEach((f) => allRepoIds.push(f.id));
}
const user = new UserModel({
accessTokens: {
github: r.accessToken,
},
externalIDs: {
github: r.profile.id,
},
username: r.username,
emails: r.profile.emails?.map((email) => {
return { email: email.value, default: false };
}),
photo: r.profile.photos[0]?.value,
repositories: allRepoIds,
default: {
terms: r.default?.terms,
options: r.default?.options,
},
});
if (user.emails?.length) user.emails[0].default = true;
await user.save();
}
console.log("Import Repositories");
const repoQuery = oldDB.collection("repositories").find();
const totalRepository = await repoQuery.count();
index = 0;
while (await repoQuery.hasNext()) {
const r = await repoQuery.next();
if (!r.id) continue;
index++;
console.log(
`Import Repository [${index}/${totalRepository}]: ${r.fullName}`
);
let find = await RepositoryModel.findOne({
externalId: "gh_" + r.id,
});
if (find == null) {
find = new RepositoryModel({
externalId: "gh_" + r.id,
name: r.fullName,
url: r.html_url,
size: r.size,
defaultBranch: r.default_branch,
});
}
if (r.branches) {
const branches = [...Object.values(r.branches)].map((b: any) => {
const o: any = { name: b.name, commit: b.commit.sha };
if (b.name == find.defaultBranch) {
o.readme = r.readme;
}
return o;
});
find.branches = branches;
}
await find.save();
}
console.log("Import Anonymized Repositories");
const anoQuery = oldDB.collection("anonymized_repositories").find();
const totalAno = await anoQuery.count();
index = 0;
while (await anoQuery.hasNext()) {
const r = await anoQuery.next();
index++;
console.log(
`Import Anonymized Repository [${index}/${totalAno}]: ${r.repoId}`
);
let repo = await RepositoryModel.findOne({ name: r.fullName });
if (repo == null) {
const tmp = await oldDB
.collection("repositories")
.findOne({ fullName: r.fullName });
if (tmp) {
repo = await RepositoryModel.findOne({ externalId: "gh_" + tmp.id });
} else {
console.error(`Repository ${r.fullName} is not found (renamed)`);
}
}
let size = { storage: 0, file: 0 };
function recursiveCount(files) {
const out = { storage: 0, file: 0 };
for (const name in files) {
const file = files[name];
if (file.size && file.sha && parseInt(file.size) == file.size) {
out.storage += file.size as number;
out.file++;
} else if (typeof file == "object") {
const r = recursiveCount(file);
out.storage += r.storage;
out.file += r.file;
}
}
return out;
}
if (r.originalFiles) {
size = recursiveCount(r.originalFiles);
}
const owner = await UserModel.findOne({ username: r.owner }).select("_id");
await new AnonymizedRepositoryModel({
repoId: r.repoId,
status: r.status,
anonymizeDate: r.anonymizeDate,
lastView: r.lastView,
pageView: r.pageView,
owner: owner?.id,
size,
source: {
accessToken: r.token,
type: r.options.mode == "download" ? "GitHubDownload" : "GitHubStream",
branch: r.branch,
commit: r.commit,
repositoryId: repo?.id,
repositoryName: r.fullName,
},
options: {
terms: r.terms,
expirationMode: r.options.expirationMode,
expirationDate: r.options.expirationDate
? new Date(r.options.expirationDate)
: null,
update: r.options.update,
image: r.options.image,
pdf: r.options.pdf,
notebook: r.options.notebook,
loc: r.options.loc,
link: r.options.link,
page: r.options.page,
pageSource: r.options.pageSource,
},
}).save();
}
console.log("Import finished!");
setTimeout(() => process.exit(), 5000);
})();

View File

@@ -0,0 +1,40 @@
receivers:
otlp:
protocols:
grpc:
exporters:
prometheus:
endpoint: "0.0.0.0:8889"
const_labels:
label1: value1
debug:
otlp:
endpoint: jaeger:4317
tls:
insecure: true
processors:
batch:
extensions:
health_check:
pprof:
endpoint: :1888
zpages:
endpoint: :55679
service:
extensions: [health_check, pprof, zpages]
pipelines:
traces:
receivers: [otlp]
exporters: [debug, otlp]
metrics:
receivers: [otlp]
exporters: [debug, prometheus]
logs:
receivers: [otlp]
exporters: [debug]

29
opentelemetry.js Normal file
View File

@@ -0,0 +1,29 @@
const opentelemetry = require("@opentelemetry/sdk-node");
const {
getNodeAutoInstrumentations,
} = require("@opentelemetry/auto-instrumentations-node");
const {
OTLPTraceExporter,
} = require("@opentelemetry/exporter-trace-otlp-grpc");
const {
OTLPMetricExporter,
} = require("@opentelemetry/exporter-metrics-otlp-grpc");
const { PeriodicExportingMetricReader } = require("@opentelemetry/sdk-metrics");
const { diag, DiagConsoleLogger, DiagLogLevel } = require("@opentelemetry/api");
// diag.setLogger(new DiagConsoleLogger(), DiagLogLevel.INFO);
const sdk = new opentelemetry.NodeSDK({
serviceName: process.env.SERVICE_NAME || "Anonymous-GitHub",
logRecordProcessor: getNodeAutoInstrumentations().logRecordProcessor,
traceExporter: new OTLPTraceExporter({
url: "http://opentelemetry:4317/v1/traces",
}),
metricReader: new PeriodicExportingMetricReader({
exporter: new OTLPMetricExporter({
url: "http://opentelemetry:4317/v1/metrics",
}),
}),
instrumentations: [getNodeAutoInstrumentations()],
});
sdk.start();

23925
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,16 +1,16 @@
{
"name": "@tdurieux/anonymous_github",
"version": "2.1.1",
"version": "2.2.0",
"description": "Anonymise Github repositories for double-anonymous reviews",
"bin": {
"anonymous_github": "build/cli.js"
"anonymous_github": "build/cli/index.js"
},
"scripts": {
"test": "mocha --reporter spec",
"start": "node --inspect=5858 -r ts-node/register ./index.ts",
"dev": "nodemon --transpile-only index.ts",
"migrateDB": "ts-node --transpile-only migrateDB.ts",
"build": "tsc"
"start": "node --inspect=5858 -r ts-node/register ./src/server/index.ts",
"dev": "nodemon --transpile-only ./src/server/index.ts",
"build": "rm -rf build && tsc && gulp",
"knip": "knip"
},
"repository": {
"type": "git",
@@ -30,60 +30,72 @@
"build"
],
"dependencies": {
"@octokit/oauth-app": "^4.1.0",
"@octokit/rest": "^19.0.5",
"@pm2/io": "^5.0.0",
"archiver": "^5.3.1",
"aws-sdk": "^2.1238.0",
"bullmq": "^2.3.2",
"@aws-sdk/client-s3": "^3.540.0",
"@aws-sdk/lib-storage": "^3.540.0",
"@mongodb-js/zstd": "^1.2.0",
"@octokit/rest": "^20.0.2",
"@opentelemetry/api": "^1.8.0",
"@opentelemetry/auto-instrumentations-node": "^0.43.0",
"@opentelemetry/exporter-metrics-otlp-grpc": "^0.49.1",
"@opentelemetry/exporter-metrics-otlp-proto": "^0.49.1",
"@opentelemetry/exporter-trace-otlp-grpc": "^0.49.1",
"@opentelemetry/exporter-trace-otlp-proto": "^0.49.1",
"@opentelemetry/sdk-metrics": "^1.22.0",
"@opentelemetry/sdk-node": "^0.49.1",
"@opentelemetry/sdk-trace-node": "^1.22.0",
"@smithy/node-http-handler": "^2.5.0",
"archiver": "^5.3.2",
"bullmq": "^2.4.0",
"cacheable-lookup": "^5.0.3",
"compression": "^1.7.4",
"connect-redis": "^6.1.3",
"decompress-stream-to-s3": "^1.3.1",
"dotenv": "^16.0.3",
"express": "^4.18.2",
"express-rate-limit": "^6.6.0",
"express-session": "^1.17.3",
"express-slow-down": "^1.5.0",
"got": "^11.8.5",
"inquirer": "^8.2.5",
"istextorbinary": "^6.0.0",
"marked": "^4.1.1",
"connect-redis": "^7.0.1",
"crypto-js": "^4.2.0",
"decompress-stream-to-s3": "^2.1.1",
"dotenv": "^16.4.5",
"express": "^4.19.2",
"express-rate-limit": "^6.11.2",
"express-session": "^1.18.0",
"express-slow-down": "^2.0.1",
"got": "^11.8.6",
"inquirer": "^8.2.6",
"istextorbinary": "^9.5.0",
"marked": "^5.1.2",
"mime-types": "^2.1.35",
"mongoose": "^6.6.7",
"node-schedule": "^2.1.0",
"mongoose": "^7.6.10",
"node-schedule": "^2.1.1",
"parse-github-url": "^1.0.2",
"passport": "^0.6.0",
"passport-github2": "^0.1.12",
"rate-limit-redis": "^3.0.1",
"redis": "^4.3.1",
"textextensions": "^5.15.0",
"ts-custom-error": "^3.3.0",
"unzip-stream": "^0.3.1",
"xml-flow": "^1.0.4"
"rate-limit-redis": "^4.2.0",
"redis": "^4.6.13",
"ts-custom-error": "^3.3.1",
"unzip-stream": "^0.3.1"
},
"devDependencies": {
"@types/archiver": "^5.3.1",
"@types/compression": "^1.7.1",
"@types/connect-redis": "^0.0.18",
"@types/express": "^4.17.14",
"@types/express-rate-limit": "^6.0.0",
"@types/express-session": "^1.17.5",
"@types/express-slow-down": "^1.3.2",
"@types/archiver": "^5.3.4",
"@types/compression": "^1.7.5",
"@types/crypto-js": "^4.2.2",
"@types/express": "^4.17.21",
"@types/express-session": "^1.18.0",
"@types/got": "^9.6.12",
"@types/inquirer": "^8.0.0",
"@types/marked": "^4.0.7",
"@types/mime-types": "^2.1.0",
"@types/parse-github-url": "^1.0.0",
"@types/passport": "^1.0.11",
"@types/passport-github2": "^1.2.5",
"@types/rate-limit-redis": "^1.7.4",
"@types/tar-fs": "^2.0.1",
"@types/unzip-stream": "^0.3.1",
"@types/xml-flow": "^1.0.1",
"chai": "^4.3.6",
"mocha": "^10.1.0",
"ts-node": "^10.9.1",
"typescript": "^4.8.4"
"@types/inquirer": "^8.2.10",
"@types/marked": "^5.0.2",
"@types/mime-types": "^2.1.4",
"@types/node-schedule": "^2.1.6",
"@types/parse-github-url": "^1.0.3",
"@types/passport": "^1.0.16",
"@types/passport-github2": "^1.2.9",
"@types/unzip-stream": "^0.3.4",
"gulp": "^5.0.0",
"gulp-clean-css": "^4.3.0",
"gulp-concat": "^2.6.1",
"gulp-order": "^1.2.0",
"gulp-uglify": "^3.0.2",
"knip": "^5.1.0",
"mocha": "^10.4.0",
"nodemon": "^3.1.0",
"ts-node": "^10.9.2",
"typescript": "^5.4.3"
},
"nodemonConfig": {
"ignore": [

6
prometheus.yaml Normal file
View File

@@ -0,0 +1,6 @@
scrape_configs:
- job_name: 'otel-collector'
scrape_interval: 10s
static_configs:
- targets: ['opentelemetry:8889']
- targets: ['opentelemetry:8888']

9
public/css/all.min.css vendored Normal file

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,123 @@
/**
* okaidia theme for JavaScript, CSS and HTML
* Loosely based on Monokai textmate theme by http://www.monokai.nl/
* @author ocodia
*/
code[class*="language-"],
pre[class*="language-"] {
color: #f8f8f2;
background: none;
text-shadow: 0 1px rgba(0, 0, 0, 0.3);
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
font-size: 1em;
text-align: left;
white-space: pre;
word-spacing: normal;
word-break: normal;
word-wrap: normal;
line-height: 1.5;
-moz-tab-size: 4;
-o-tab-size: 4;
tab-size: 4;
-webkit-hyphens: none;
-moz-hyphens: none;
-ms-hyphens: none;
hyphens: none;
}
/* Code blocks */
pre[class*="language-"] {
padding: 1em;
margin: .5em 0;
overflow: auto;
border-radius: 0.3em;
}
:not(pre) > code[class*="language-"],
pre[class*="language-"] {
background: #272822;
}
/* Inline code */
:not(pre) > code[class*="language-"] {
padding: .1em;
border-radius: .3em;
white-space: normal;
}
.token.comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #8292a2;
}
.token.punctuation {
color: #f8f8f2;
}
.token.namespace {
opacity: .7;
}
.token.property,
.token.tag,
.token.constant,
.token.symbol,
.token.deleted {
color: #f92672;
}
.token.boolean,
.token.number {
color: #ae81ff;
}
.token.selector,
.token.attr-name,
.token.string,
.token.char,
.token.builtin,
.token.inserted {
color: #a6e22e;
}
.token.operator,
.token.entity,
.token.url,
.language-css .token.string,
.style .token.string,
.token.variable {
color: #f8f8f2;
}
.token.atrule,
.token.attr-value,
.token.function,
.token.class-name {
color: #e6db74;
}
.token.keyword {
color: #66d9ef;
}
.token.regex,
.token.important {
color: #fd971f;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}

View File

@@ -133,6 +133,12 @@ a:hover {
color: var(--link-hover-color);
}
.markdown-body .emoji {
height: 1.3em;
margin: 0;
vertical-align: -0.1em;
}
.navbar {
background: var(--header-bg-color) !important;
}
@@ -428,6 +434,11 @@ notebook {
padding-left: 100px;
}
.nb-output th,
.nb-output td {
border: 1px solid var(--border-color) !important;
}
.floatingchat-container-wrap {
left: inherit !important;
bottom: inherit !important;
@@ -579,6 +590,7 @@ pre,
code {
font-family: "Fira Code", "Courier New", Courier, monospace;
line-height: 1.1;
color: var(--color)
}
.diff-lines,

View File

@@ -3,12 +3,12 @@
"short_name": "Anonymous Github",
"icons": [
{
"src": "/android-chrome-192x192.png",
"src": "/favicon/android-chrome-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/android-chrome-256x256.png",
"src": "/favicon/android-chrome-256x256.png",
"sizes": "256x256",
"type": "image/png"
}

View File

@@ -1,5 +1,9 @@
{
"ERRORS": {
"unknown_error": "Unknown error, contact the admin.",
"unreachable": "Anonymous GitHub is unreachable, contact the admin.",
"request_error": "Unable to download the file, check your connection or contact the admin.",
"repo_access_limited": "Access to repository limited by org.",
"repo_not_found": "The repository is not found.",
"repo_not_accessible": "Anonymous GitHub is unable to or is forbidden to access the repository.",
"repository_expired": "The repository is expired",

View File

@@ -33,51 +33,7 @@
<meta name="msapplication-config" content="/favicon/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<!-- CSS -->
<link rel="stylesheet" href="/css/bootstrap.min.css" />
<link rel="stylesheet" href="/css/font-awesome.min.css" />
<link rel="stylesheet" href="/css/color-schema.css" />
<link rel="stylesheet" href="/css/style.css" />
<link rel="stylesheet" href="/css/notebook.css" />
<link rel="stylesheet" href="/css/prism.css" />
<link rel="stylesheet" href="/css/katex.min.css" />
<link rel="stylesheet" href="/css/github-markdown.min.css" />
<!-- JS -->
<script src="/script/external/angular.min.js"></script>
<script src="/script/external/angular-translate.min.js"></script>
<script src="/script/external/angular-translate-loader-static-files.min.js"></script>
<script src="/script/external/angular-sanitize.min.js"></script>
<script src="/script/external/angular-route.min.js"></script>
<script src="/script/external/ana.min.js"></script>
<script src="/script/external/jquery-3.4.1.min.js"></script>
<script src="/script/external/popper.min.js"></script>
<script src="/script/external/bootstrap.min.js"></script>
<script src="/script/external/pdf.compat.js"></script>
<script src="/script/external/pdf.js"></script>
<script src="/script/external/ace/ace.js"></script>
<script src="/script/external/ui-ace.min.js"></script>
<script src="/script/langColors.js"></script>
<!-- Notebook -->
<script src="/script/external/marked.min.js"></script>
<script src="/script/external/purify.min.js"></script>
<script src="/script/external/ansi_up.min.js"></script>
<script src="/script/external/prism.min.js"></script>
<script src="/script/external/katex.min.js"></script>
<script src="/script/external/katex-auto-render.min.js"></script>
<script src="/script/external/notebook.min.js"></script>
<script src="/script/external/org.js"></script>
<!-- Anonymous GitHub scripts -->
<script src="/script/utils.js"></script>
<script src="/script/ng-pdfviewer.min.js"></script>
<script src="/script/admin.js"></script>
<script src="/script/app.js"></script>
<link rel="stylesheet" href="/css/all.min.css" />
</head>
<body keypress-events class="d-flex flex-column">
<ng-include src="'partials/header.htm'"></ng-include>
@@ -112,6 +68,11 @@
</div>
</div>
<script src="/script/bundle.min.js"></script>
<script>
ace.config.set("basePath", "/script/external/ace/");
PDFJS.workerSrc = "/script/external/pdf.worker.js";
</script>
<script src="https://storage.ko-fi.com/cdn/scripts/overlay-widget.js"></script>
<script>
kofiWidgetOverlay.draw("tdurieux", {

View File

@@ -148,5 +148,79 @@
There is no job to display.
</li>
</ul>
<h1>Remove Cache</h1>
<ul class="p-0 m-0 w-100">
<li
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
ng-repeat="job in removeCaches as filteredRemoveCache"
>
<div class="w-100">
<div class="">
<h3>
<a target="__blank" ng-href="/r/{{job.id}}" ng-bind="job.id"></a>
<span class="badge" ng-bind="job.progress.status | title"></span>
</h3>
</div>
<div class="color-text-secondary mb-1">
<span ng-if="job.timestamp">
Created on:
<span ng-bind="job.timestamp | humanTime"></span>
</span>
<span ng-if="job.finishedOn">
Finished on:
<span ng-bind="job.finishedOn | humanTime"></span>
</span>
<span ng-if="job.processedOn">
Processed on:
<span ng-bind="job.processedOn | humanTime"></span>
</span>
</div>
<div>
<pre
ng-repeat="stack in job.stacktrace track by $index"
><code ng-bind="stack"></code></pre>
</div>
</div>
<div class="d-flex">
<div class="dropdown">
<button
class="btn black_border dropdown-toggle btn-sm"
type="button"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Actions
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a
class="dropdown-item"
href="#"
ng-click="removeJob('cache', job)"
>
<i class="fas fa-trash-alt"></i> Remove
</a>
<a
class="dropdown-item"
href="#"
ng-click="retryJob('cache', job)"
>
<i class="fas fa-sync"></i> Retry
</a>
<a class="dropdown-item" href="/anonymize/{{job.id}}">
<i class="far fa-edit" aria-hidden="true"></i> Edit
</a>
</div>
</div>
</div>
</li>
<li
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
ng-if="filteredRemoveCache.length == 0"
>
There is no job to display.
</li>
</ul>
</div>
</div>

View File

@@ -313,6 +313,9 @@
Actions
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
<i class="fas fa-trash-alt"></i> Remove Cache
</a>
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
<i class="far fa-edit" aria-hidden="true"></i> Edit
</a>

View File

@@ -1,9 +1,15 @@
<div class="container page">
<div class="row">
<h1>
<img ng-src="{{userInfo.photo}}" ng-if="userInfo.photo" width="30" height="30" class="rounded-circle ng-scope">
<img
ng-src="{{userInfo.photo}}"
ng-if="userInfo.photo"
width="30"
height="30"
class="rounded-circle ng-scope"
/>
{{userInfo.username}}
<span class="badge"><span ng-bind="userInfo.status | title"></span>
<span class="badge"><span ng-bind="userInfo.status | title"></span></span>
</h1>
<div class="row mb-3 m-0 py-2 border">
<div class="col-2 font-weight-bold">ID</div>
@@ -16,12 +22,47 @@
<div class="col-10">{{userInfo.accessTokens.github}}</div>
<div class="col-2 font-weight-bold">Github</div>
<div class="col-10"><a ng-href="https://github.com/{{userInfo.username}}">{{userInfo.username}}</a></div>
<div class="col-10">
<a ng-href="https://github.com/{{userInfo.username}}"
>{{userInfo.username}}</a
>
</div>
<div class="col-2 font-weight-bold">Github Repositories</div>
<div class="col-10">{{userInfo.repositories.length}}</a></div>
<div class="col-10" ng-click="showRepos =!showRepos">
{{userInfo.repositories.length}}
</div>
<button
class="btn btn-primary m-1 mx-3"
ng-click="getGitHubRepositories()"
>
Regresh Repositories
</button>
<ul class="m-0 col-12" ng-if="showRepos">
<li
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"
ng-repeat="repo in userInfo.repositories"
>
<div class="w-100">
<div class="">
{{repo.name}}
</div>
<div class="color-text-secondary mt-2">
<span
class="ml-0 mr-3"
title="Size: {{::repo.size | humanFileSize}}"
data-toggle="tooltip"
data-placement="bottom"
>
<i class="fas fa-database"></i> {{::repo.size |
humanFileSize}}</span
>
</div>
</div>
</li>
</ul>
</div>
<h3>Repositories {{repositories.length}}</h3>
<div class="border-bottom color-border-secondary py-3 w-100">
<div class="d-flex flex-items-start w-100">
@@ -245,6 +286,64 @@
>
</div>
</div>
<div class="d-flex">
<div class="dropdown">
<button
class="btn black_border dropdown-toggle btn-sm"
type="button"
id="dropdownMenuButton"
data-toggle="dropdown"
aria-haspopup="true"
aria-expanded="false"
>
Actions
</button>
<div class="dropdown-menu" aria-labelledby="dropdownMenuButton">
<a class="dropdown-item" href="#" ng-click="removeCache(repo)">
<i class="fas fa-trash-alt"></i> Remove Cache
</a>
<a class="dropdown-item" href="/anonymize/{{repo.repoId}}">
<i class="far fa-edit" aria-hidden="true"></i> Edit
</a>
<a
class="dropdown-item"
href="#"
ng-show="repo.status == 'ready' || repo.status == 'error'"
ng-click="updateRepository(repo)"
>
<i class="fas fa-sync"></i> Force update
</a>
<a
class="dropdown-item"
href="#"
ng-show="repo.status == 'removed'"
ng-click="updateRepository(repo)"
>
<i class="fas fa-check-circle"></i>
Enable
</a>
<a
class="dropdown-item"
href="#"
ng-show="repo.status == 'ready'"
ng-click="removeRepository(repo)"
>
<i class="fas fa-trash-alt"></i> Remove
</a>
<a class="dropdown-item" href="/r/{{repo.repoId}}/">
<i class="fa fa-eye" aria-hidden="true"></i> View Repo
</a>
<a
class="dropdown-item"
href="/w/{{repo.repoId}}/"
target="_self"
ng-if="repo.options.page && repo.status == 'ready'"
>
<i class="fas fa-globe"></i> View Page
</a>
</div>
</div>
</div>
</li>
<li
class="col-12 d-flex px-0 py-3 border-bottom color-border-secondary"

View File

@@ -13,14 +13,9 @@
name="anonymize"
novalidate
>
<h5 class="card-title">Anonymize a repository</h5>
<h6 class="card-subtitle mb-2 text-muted">
Fill the information to anonymize! It will only take 5min.
</h6>
<h2>Source</h2>
<h3 class="card-title mb-3">Anonymize your repository</h3>
<!-- repoUrl -->
<div class="form-group">
<label for="repoUrl">Type the url of your repository</label>
<div class="form-group mb-0">
<input
type="text"
class="form-control"
@@ -28,6 +23,7 @@
id="repoUrl"
ng-class="{'is-invalid': anonymize.repoUrl.$invalid}"
ng-model="repoUrl"
placeholder="URL of your GitHub repository"
ng-model-options="{ debounce: {default: 1000, blur: 0, click: 0}, updateOn: 'default blur click' }"
ng-change="repoSelected()"
/>
@@ -58,37 +54,6 @@
{{repoUrl}} is already anonymized
</div>
</div>
<!-- select repo -->
<div class="form-group" ng-hide="repoUrl">
<label for="repositories">Or select one of your repository</label>
<div class="input-group mb-3">
<select
class="form-control"
id="repositories"
name="repositories"
ng-model="repoUrl"
ng-change="repoSelected()"
>
<option selected value="">None</option>
<option
ng-repeat="repo in repositories|orderBy:'fullName'"
value="https://github.com/{{ repo.fullName }}"
ng-bind="repo.fullName"
></option>
</select>
<div class="input-group-append">
<button
class="btn btn-outline-secondary"
ng-click="getRepositories(true)"
title="Refresh!"
data-toggle="tooltip"
data-placement="bottom"
>
<i class="fa fa-undo"></i>
</button>
</div>
</div>
</div>
<div ng-show="repoUrl">
<!-- Branch -->
<div class="form-group">
@@ -386,29 +351,6 @@
>Display Notebooks</label
>
</div>
<div class="form-group">
<label for="mode">Proxy mode</label>
<select
class="form-control"
id="mode"
name="mode"
ng-model="source.type"
>
<option value="GitHubStream" selected>Stream</option>
<option value="GitHubDownload">Download</option>
</select>
<small class="form-text text-muted"
>How the repository will be anonymized. Stream mode
will request the content on the flight. This is the
only option for repositories bigger than
{{site_options.MAX_REPO_SIZE * 1024| humanFileSize}}.
This repository is {{details.size * 8 *1024 |
humanFileSize}}. Download will download the repository
the repository on the anonymous.4open.science server,
it is faster and offer more features.</small
>
</div>
</div>
<div class="form-group">
<div class="form-check">

View File

@@ -242,7 +242,7 @@
<div class="d-flex d-inline-flex mt-2">
<div class="alert alert-info alert-dismissible my-0 ml-1" ng-show="!v" role="alert" ng-repeat="(f, v) in filters.status">
<strong>{{f | title}}</strong>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<button type="button" class="close" data-dismiss="alert" aria-label="Close" ng-click="filters.status[f] = true;">
<span aria-hidden="true">&times;</span>
</button>
</div>

View File

@@ -1,9 +1,14 @@
<div class="container-fluid h-100">
<div class="row h-100">
<div class="leftCol shadow p-1 overflow-auto" ng-show="files">
<div class="leftCol shadow p-1 overflow-auto" ng-show="files.length">
<tree class="files" file="files"></tree>
<div class="bottom column">
<div class="last-update">
<div
class="last-update"
data-toggle="tooltip"
data-placement="top"
title="{{options.lastUpdateDate}}"
>
Last Update: {{options.lastUpdateDate|date}}
</div>
</div>
@@ -17,9 +22,23 @@
</ol>
<div class="">
<a
ng-if="options.isAdmin || options.isOwner"
ng-href="/anonymize/{{repoId}}"
class="btn btn-outline-primary btn-sm"
>Edit</a
>
<a
ng-show="content != null"
ng-href="{{url}}"
target="__self"
class="btn btn-outline-primary btn-sm"
>View raw</a
>
<a
ng-show="content != null"
ng-href="{{url}}&download=true"
target="__self"
class="btn btn-outline-primary btn-sm"
>Download file</a
>
<a
@@ -29,6 +48,13 @@
class="btn btn-outline-primary btn-sm"
>Download Repository</a
>
<a
ng-if="options.hasWebsite"
ng-href="/w/{{repoId}}/"
target="__self"
class="btn btn-outline-primary btn-sm"
>Website</a
>
</div>
</div>
<div class="align-items-stretch h-100 w-100 overflow-auto">

View File

@@ -13,42 +13,6 @@
role="tablist"
aria-multiselectable="true"
>
<div class="panel panel-default mb-4">
<div class="panel-heading p-3" role="tab" id="heading0">
<h3 class="panel-title">
<a
class="collapsed"
role="button"
title=""
data-toggle="collapse"
data-parent="#faq"
href="#download"
aria-expanded="true"
aria-controls="download"
>
Can I download the repository?
</a>
</h3>
</div>
<div
id="download"
class="panel-collapse collapse"
role="tabpanel"
aria-labelledby="heading0"
>
<div class="panel-body p-3">
<p>
It is currently not possible to download an anonymized
repository neither to clone it.
It is technically possible to implement however it
would require additional processing power and storage.
I am currently not able to cover the cost of this feature.
If you want to see this feature on Anonymous GitHub, please consider doing a donation.
</p>
</div>
</div>
</div>
<div class="panel panel-default mb-4">
<div class="panel-heading p-3" role="tab" id="heading6">
<h3 class="panel-title">
@@ -75,11 +39,9 @@
<div class="panel-body p-3">
<p>
<ul>
<li>
Anonymous GitHub does not allow to download the repository.
</li>
<li>
Anonymous GitHub only anonymizes textual files.
It does not support the use of a static site generator, such as Jekyll, with GitHub Pages (although Markdown files are converted to HTML without any special formatting).
</li>
<li>
Anonymous GitHub does not support files that are larger than 8Mo.
@@ -119,12 +81,7 @@
<div class="panel-body p-3">
<p>
Anonymous Github is able to display pure textual files, such as text or source code. It can also render images, PDFs, and notbooks.
However, only textual based files are anonymized. Anonymous Github considers the following file format as textual:
</p>
<p>
<ul>
<li ng-repeat="format in supportedFileTypes" ng-bind="format"></li>
</ul>
However, only textual based files are anonymized. Anonymous Github analyzes the content of the file to detect if it is textual or not.
</p>
</div>
</div>

View File

@@ -137,7 +137,7 @@
aria-expanded="false"
>
<img
src="{{user.photo}}"
ng-src="{{user.photo}}"
ng-if="user.photo"
width="30"
height="30"

View File

@@ -96,7 +96,8 @@
The reviewers can explore your repository with ease, the source code
is highlighted, PDFs, images, Notebook are rendered. The goal is to
make is as easy as possible for the reviewer to explore and review
the repository. GitHub pages are also supported.
the repository. <a href="https://pages.github.com">GitHub Pages</a>
is also supported, but not static site generators, such as Jekyll.
</p>
</div>
<div class="col-md-5">

View File

@@ -2,10 +2,14 @@
<div ng-if="type == 'html'" ng-bind-html="content" class="file-content markdown-body"></div>
<div ng-if="type == 'code' && content != null" ui-ace="aceOption" ng-model="content"></div>
<img ng-if="type == 'image'" class="image-content" ng-src="{{url}}"></img>
<iframe class="h-100 overflow-auto w-100 b-0" ng-if="type == 'media'" ng-src="{{url}}"></iframe>
<div class="h-100 overflow-auto" ng-if="type == 'pdf'">
<pdfviewer class="h-100 overflow-auto" src="{{url}}" id="viewer"></pdfviewer>
</div>
<div ng-if="type == 'audio'"><audio controls="controls"><source src="{{url}}" /></audio></div>
<div ng-if="type == 'IPython'"><notebook file="url"></notebook></div>
<div ng-if="type == 'error'" class="file-error container d-flex h-100"><h1 class="display-1 m-auto" translate="ERRORS.{{content}}">Error</h1></div></div>
<div ng-if="type == 'loading' && !error" class="file-error container d-flex h-100"><h1 class="display-1 m-auto">Loading...</h1></div></div>
<div ng-if="content == null" class="file-error container d-flex h-100"><h1 class="display-1 m-auto">Empty file!</h1></div>
<div ng-if="type == 'empty'" class="file-error container d-flex h-100"><h1 class="display-1 m-auto">Empty repository!</h1></div>
<div ng-if="content == null && type != 'empty'" class="file-error container d-flex h-100"><h1 class="display-1 m-auto">Empty file!</h1></div>
<div ng-if="type == 'binary'" class="file-error container d-flex h-100"><h1 class="display-1 m-auto">Unsupported binary file. You can download the file: <a target="_blank" ng-href="{{url}}&download=true">here</a>.</h1></div>

View File

@@ -21,10 +21,9 @@
>
<span>
{{repo.status | title}}
<span
ng-if="repo.status == 'download' && repo.statusMessage"
ng-bind="repo.statusMessage | humanFileSize"
></span>
<span ng-if="repo.statusMessage"
>: {{repo.statusMessage | title}}</span
>
</span>
</div>
</div>
@@ -56,10 +55,16 @@
</p>
</section>
<hr />
<section class="py-4">
<h2>Support the project</h2>
<h2 class="md-1">Support Anonymous GitHub</h2>
<iframe
id="kofiframe"
src="https://ko-fi.com/tdurieux/?hidefeed=true&widget=true&embed=true&preview=true"
style="border: none; width: 100%"
height="650"
title="tdurieux"
></iframe>
<div class="row text-center">
<div class="col-lg-4">

View File

@@ -20,22 +20,56 @@ angular
$scope.query = {
page: 1,
limit: 25,
sort: "source.repositoryName",
sort: "lastView",
search: "",
ready: true,
expired: true,
removed: true,
ready: false,
expired: false,
removed: false,
error: true,
preparing: true,
};
$scope.removeCache = (repo) => {
$http.delete("/api/admin/repos/" + repo.repoId).then(
(res) => {
$scope.$apply();
},
(err) => {
console.error(err);
}
);
};
$scope.updateRepository = (repo) => {
const toast = {
title: `Refreshing ${repo.repoId}...`,
date: new Date(),
body: `The repository ${repo.repoId} is going to be refreshed.`,
};
$scope.toasts.push(toast);
repo.s;
$http.post(`/api/repo/${repo.repoId}/refresh`).then(
(res) => {
if (res.data.status == "ready") {
toast.title = `${repo.repoId} is refreshed.`;
} else {
toast.title = `Refreshing of ${repo.repoId}.`;
}
},
(error) => {
toast.title = `Error during the refresh of ${repo.repoId}.`;
toast.body = error.body;
}
);
};
function getRepositories() {
$http.get("/api/admin/repos", { params: $scope.query }).then(
(res) => {
$scope.total = res.data.total;
$scope.totalPage = Math.ceil(res.data.total / $scope.query.limit);
$scope.repositories = res.data.results;
$scope.$apply();
},
(err) => {
console.error(err);
@@ -138,7 +172,7 @@ angular
return false;
};
function getUserRepositories(username) {
$http.get("/api/admin/users/" + username + "/repos", {}).then(
(res) => {
@@ -162,6 +196,51 @@ angular
getUser($routeParams.username);
getUserRepositories($routeParams.username);
$scope.removeCache = (repo) => {
$http.delete("/api/admin/repos/" + repo.repoId).then(
(res) => {
$scope.$apply();
},
(err) => {
console.error(err);
}
);
};
$scope.updateRepository = (repo) => {
const toast = {
title: `Refreshing ${repo.repoId}...`,
date: new Date(),
body: `The repository ${repo.repoId} is going to be refreshed.`,
};
$scope.toasts.push(toast);
repo.s;
$http.post(`/api/repo/${repo.repoId}/refresh`).then(
(res) => {
if (res.data.status == "ready") {
toast.title = `${repo.repoId} is refreshed.`;
} else {
toast.title = `Refreshing of ${repo.repoId}.`;
}
},
(error) => {
toast.title = `Error during the refresh of ${repo.repoId}.`;
toast.body = error.body;
}
);
};
$scope.getGitHubRepositories = (force) => {
$http
.get(`/api/user/${$scope.userInfo.username}/all_repositories`, {
params: { force: "1" },
})
.then((res) => {
$scope.userInfo.repositories = res.data;
});
};
let timeClear = null;
$scope.$watch(
"query",
@@ -247,6 +326,7 @@ angular
(res) => {
$scope.downloadJobs = res.data.downloadQueue;
$scope.removeJobs = res.data.removeQueue;
$scope.removeCaches = res.data.cacheQueue;
},
(err) => {
console.error(err);

File diff suppressed because it is too large Load Diff

9
public/script/bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1879
public/script/external/github-emojis.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n),a=function(e,t,r){for(var n=r,o=0,a=e.length;n<t.length;){var i=t[n];if(o<=0&&t.slice(n,n+a)===e)return n;"\\"===i?n++:"{"===i?o++:"}"===i&&o--,n++}return-1},i=function(e,t,r,n){for(var o=[],i=0;i<e.length;i++)if("text"===e[i].type){var l=e[i].data,d=!0,s=0,f=void 0;for(-1!==(f=l.indexOf(t))&&(s=f,o.push({type:"text",data:l.slice(0,s)}),d=!1);;){if(d){if(-1===(f=l.indexOf(t,s)))break;o.push({type:"text",data:l.slice(s,f)}),s=f}else{if(-1===(f=a(r,l,s+t.length)))break;o.push({type:"math",data:l.slice(s+t.length,f),rawData:l.slice(s,f+r.length),display:n}),s=f+r.length}d=!d}o.push({type:"text",data:l.slice(s)})}else o.push(e[i]);return o},l=function(e,t){var r=function(e,t){for(var r=[{type:"text",data:e}],n=0;n<t.length;n++){var o=t[n];r=i(r,o.left,o.right,o.display||!1)}return r}(e,t.delimiters);if(1===r.length&&"text"===r[0].type)return null;for(var n=document.createDocumentFragment(),a=0;a<r.length;a++)if("text"===r[a].type)n.appendChild(document.createTextNode(r[a].data));else{var l=document.createElement("span"),d=r[a].data;t.displayMode=r[a].display;try{t.preProcess&&(d=t.preProcess(d)),o.a.render(d,l,t)}catch(e){if(!(e instanceof o.a.ParseError))throw e;t.errorCallback("KaTeX auto-render: Failed to parse `"+r[a].data+"` with ",e),n.appendChild(document.createTextNode(r[a].rawData));continue}n.appendChild(l)}return n};t.default=function(e,t){if(!e)throw new Error("No element provided to render");var r={};for(var n in t)t.hasOwnProperty(n)&&(r[n]=t[n]);r.delimiters=r.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\[",right:"\\]",display:!0}],r.ignoredTags=r.ignoredTags||["script","noscript","style","textarea","pre","code","option"],r.ignoredClasses=r.ignoredClasses||[],r.errorCallback=r.errorCallback||console.error,r.macros=r.macros||{},function e(t,r){for(var n=0;n<t.childNodes.length;n++){var o=t.childNodes[n];if(3===o.nodeType){var a=l(o.textContent,r);a&&(n+=a.childNodes.length-1,t.replaceChild(a,o))}else 1===o.nodeType&&function(){var t=" "+o.className+" ";-1===r.ignoredTags.indexOf(o.nodeName.toLowerCase())&&r.ignoredClasses.every(function(e){return-1===t.indexOf(" "+e+" ")})&&e(o,r)}()}}(e,r)}}]).default});
!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("katex")):"function"==typeof define&&define.amd?define(["katex"],t):"object"==typeof exports?exports.renderMathInElement=t(require("katex")):e.renderMathInElement=t(e.katex)}("undefined"!=typeof self?self:this,(function(e){return function(){"use strict";var t={771:function(t){t.exports=e}},n={};function r(e){var o=n[e];if(void 0!==o)return o.exports;var i=n[e]={exports:{}};return t[e](i,i.exports,r),i.exports}r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,{a:t}),t},r.d=function(e,t){for(var n in t)r.o(t,n)&&!r.o(e,n)&&Object.defineProperty(e,n,{enumerable:!0,get:t[n]})},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)};var o={};return function(){r.d(o,{default:function(){return d}});var e=r(771),t=r.n(e);const n=function(e,t,n){let r=n,o=0;const i=e.length;for(;r<t.length;){const n=t[r];if(o<=0&&t.slice(r,r+i)===e)return r;"\\"===n?r++:"{"===n?o++:"}"===n&&o--,r++}return-1},i=/^\\begin{/;var a=function(e,t){let r;const o=[],a=new RegExp("("+t.map((e=>e.left.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"))).join("|")+")");for(;r=e.search(a),-1!==r;){r>0&&(o.push({type:"text",data:e.slice(0,r)}),e=e.slice(r));const a=t.findIndex((t=>e.startsWith(t.left)));if(r=n(t[a].right,e,t[a].left.length),-1===r)break;const l=e.slice(0,r+t[a].right.length),s=i.test(l)?l:e.slice(t[a].left.length,r);o.push({type:"math",data:s,rawData:l,display:t[a].display}),e=e.slice(r+t[a].right.length)}return""!==e&&o.push({type:"text",data:e}),o};const l=function(e,n){const r=a(e,n.delimiters);if(1===r.length&&"text"===r[0].type)return null;const o=document.createDocumentFragment();for(let e=0;e<r.length;e++)if("text"===r[e].type)o.appendChild(document.createTextNode(r[e].data));else{const i=document.createElement("span");let a=r[e].data;n.displayMode=r[e].display;try{n.preProcess&&(a=n.preProcess(a)),t().render(a,i,n)}catch(i){if(!(i instanceof t().ParseError))throw i;n.errorCallback("KaTeX auto-render: Failed to parse `"+r[e].data+"` with ",i),o.appendChild(document.createTextNode(r[e].rawData));continue}o.appendChild(i)}return o},s=function(e,t){for(let n=0;n<e.childNodes.length;n++){const r=e.childNodes[n];if(3===r.nodeType){let o=r.textContent,i=r.nextSibling,a=0;for(;i&&i.nodeType===Node.TEXT_NODE;)o+=i.textContent,i=i.nextSibling,a++;const s=l(o,t);if(s){for(let e=0;e<a;e++)r.nextSibling.remove();n+=s.childNodes.length-1,e.replaceChild(s,r)}else n+=a}else if(1===r.nodeType){const e=" "+r.className+" ";-1===t.ignoredTags.indexOf(r.nodeName.toLowerCase())&&t.ignoredClasses.every((t=>-1===e.indexOf(" "+t+" ")))&&s(r,t)}}};var d=function(e,t){if(!e)throw new Error("No element provided to render");const n={};for(const e in t)t.hasOwnProperty(e)&&(n[e]=t[e]);n.delimiters=n.delimiters||[{left:"$$",right:"$$",display:!0},{left:"\\(",right:"\\)",display:!1},{left:"\\begin{equation}",right:"\\end{equation}",display:!0},{left:"\\begin{align}",right:"\\end{align}",display:!0},{left:"\\begin{alignat}",right:"\\end{alignat}",display:!0},{left:"\\begin{gather}",right:"\\end{gather}",display:!0},{left:"\\begin{CD}",right:"\\end{CD}",display:!0},{left:"\\[",right:"\\]",display:!0}],n.ignoredTags=n.ignoredTags||["script","noscript","style","textarea","pre","code","option"],n.ignoredClasses=n.ignoredClasses||[],n.errorCallback=n.errorCallback||console.error,n.macros=n.macros||{},s(e,n)}}(),o=o.default}()}));

Some files were not shown because too many files have changed in this diff Show More