{"id":49659505,"url":"https://github.com/gitubpatrice/files_tech_core","last_synced_at":"2026-05-06T11:06:11.642Z","repository":{"id":355019847,"uuid":"1225947826","full_name":"gitubpatrice/files_tech_core","owner":"gitubpatrice","description":"Code partagé entre les apps Files Tech (PDF Tech, Read Files Tech, Pass Tech)","archived":false,"fork":false,"pushed_at":"2026-05-01T12:27:35.000Z","size":39,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-01T14:11:01.977Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://files-tech.com","language":"Dart","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/gitubpatrice.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":"NOTICE","maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://files-tech.com/don.php"]}},"created_at":"2026-04-30T20:16:15.000Z","updated_at":"2026-05-01T12:27:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/gitubpatrice/files_tech_core","commit_stats":null,"previous_names":["gitubpatrice/files_tech_core"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/gitubpatrice/files_tech_core","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitubpatrice%2Ffiles_tech_core","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitubpatrice%2Ffiles_tech_core/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitubpatrice%2Ffiles_tech_core/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitubpatrice%2Ffiles_tech_core/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/gitubpatrice","download_url":"https://codeload.github.com/gitubpatrice/files_tech_core/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/gitubpatrice%2Ffiles_tech_core/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32690582,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-06T08:33:17.875Z","status":"ssl_error","status_checked_at":"2026-05-06T08:33:17.221Z","response_time":117,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-06T11:06:10.617Z","updated_at":"2026-05-06T11:06:11.635Z","avatar_url":"https://github.com/gitubpatrice.png","language":"Dart","funding_links":["https://files-tech.com/don.php"],"categories":[],"sub_categories":[],"readme":"# files_tech_core\n\n[![CI](https://github.com/gitubpatrice/files_tech_core/actions/workflows/ci.yml/badge.svg)](https://github.com/gitubpatrice/files_tech_core/actions/workflows/ci.yml)\n[![License: Apache 2.0](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](LICENSE)\n[![Flutter](https://img.shields.io/badge/Flutter-stable-02569B?logo=flutter)](https://flutter.dev)\n\nCode partagé entre les apps Files Tech (PDF Tech, Read Files Tech, Pass Tech).\nPackage local Flutter (path-dependency) — **non publié sur pub.dev**.\n\n## Contenu\n\n| Module | Rôle |\n|---|---|\n| `RecentFile` + `RecentFilesService` | Liste des fichiers récents persistée dans `SharedPreferences`, robuste aux entrées corrompues |\n| `UpdateService` + `UpdateInfo` | Vérification de mises à jour via GitHub Releases, cache 12h, validation semver + host whitelist |\n| `CloudShareRow` + `CloudTargets` | Boutons de partage cloud (kDrive, Google Drive, Proton Drive) via MethodChannel |\n| `LegalSupportSections` | Sections \"Aide \u0026 support\" + \"Mentions légales\" avec whitelist de schemes (anti `intent:`/`javascript:`) |\n| `FormatUtils` | Formatage humanisé d'octets (`bytes` style FR, `bytesStorage` style EN) |\n| `PathSafe` | Validation et sanitisation de noms de fichiers (anti path-traversal) |\n\n## Usage\n\nAjouter dans le `pubspec.yaml` de l'app consommatrice :\n\n```yaml\ndependencies:\n  files_tech_core:\n    path: ../files_tech_core\n```\n\n### RecentFiles\n\n```dart\nimport 'package:files_tech_core/files_tech_core.dart';\n\nfinal svc = RecentFilesService();\nList\u003cRecentFile\u003e recents = await svc.load();\nrecents = await svc.addOrUpdate(recents, '/storage/emulated/0/Download/foo.pdf');\n```\n\n### UpdateService\n\nConfigurer un singleton par app :\n\n```dart\n// app/lib/services/app_update.dart\nconst appUpdateService = UpdateService(\n  owner: 'gitubpatrice',\n  repo: 'PDF-TECH',\n  currentVersion: '1.8.0',\n);\n\n// Usage\nfinal info = await appUpdateService.checkForUpdate();\nfinal manualCheck = await appUpdateService.checkForUpdate(force: true);\n```\n\n### CloudShareRow\n\nWrapper per-app pour injecter le nom de channel :\n\n```dart\n// app/lib/widgets/cloud_share_row.dart\nimport 'package:files_tech_core/files_tech_core.dart' as core;\n\nclass CloudShareRow extends StatelessWidget {\n  final String path;\n  const CloudShareRow({super.key, required this.path});\n  @override\n  Widget build(BuildContext context) =\u003e core.CloudShareRow(\n    path: path,\n    channelName: 'com.pdftech.pdf_tech/share',\n    alignment: WrapAlignment.center,\n  );\n}\n```\n\nCôté Kotlin, le channel doit exposer `sendToPackage` qui prend `path`, `mime`, `package`.\n\n### LegalSupportSections\n\n```dart\nconst LegalSupportSections(\n  appName: 'PDF Tech',\n  version: '1.8.0',\n)\n```\n\nL'app consommatrice doit déclarer dans son `pubspec.yaml` :\n\n```yaml\nflutter:\n  assets:\n    - assets/legal/PRIVACY.fr.md\n    - assets/legal/TERMS.fr.md\n```\n\nOverride possible des chemins via `privacyAsset` / `termsAsset`, et de\n`contactEmail` / `websiteUrl` si nécessaire.\n\n### FormatUtils\n\n```dart\nFormatUtils.bytes(1500);        // → \"1.5 Ko\"  (FR)\nFormatUtils.bytesStorage(1500); // → \"1.5 KB\"  (EN, MB sans décimale)\n```\n\n### PathSafe\n\n```dart\nPathSafe.basename('/foo/bar.pdf');         // → \"bar.pdf\"\nPathSafe.basename('..');                   // → throws ArgumentError\nPathSafe.sanitizeFileName('my:file*.txt'); // → \"my_file_.txt\"\nPathSafe.sanitizeForFs('hello world');     // → \"hello_world\" (variante FS-safe)\nPathSafe.isValidUserFileName('foo.pdf');   // → true\n```\n\n## Sécurité\n\n- Pas de secret hardcodé\n- HTTPS uniquement (`api.github.com`)\n- Schemes autorisés dans les liens : `https`, `http`, `mailto` (refus de `intent:`, `javascript:`, `file:`, etc.)\n- Refus des URIs avec `userInfo` (anti credential phishing)\n- `LaunchMode.externalApplication` (pas de browser-in-app)\n- `RecentFilesService.load` filtre silencieusement les entrées corrompues (anti DoS)\n- `UpdateService` valide `tag_name` en regex semver et whitelist le host de l'APK (`github.com` / `objects.githubusercontent.com`)\n- `mailto` strip CRLF (anti header injection)\n\n## Tests\n\n```bash\nflutter test\n```\n\n## Conventions\n\n- Versions des apps doivent rester synchronisées entre `pubspec.yaml`,\n  `AboutScreen._version` et `app_update.dart` `currentVersion`.\n- Les channels Kotlin sont par-app (`com.pdftech.pdf_tech/share`,\n  `com.readfilestech/open_file`, etc.) — déclarés dans le wrapper local.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitubpatrice%2Ffiles_tech_core","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgitubpatrice%2Ffiles_tech_core","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgitubpatrice%2Ffiles_tech_core/lists"}