[{"data":1,"prerenderedAt":2698},["ShallowReactive",2],{"blog-25-10-26":3,"surround-blog":271,"blog-list":277},{"id":4,"title":5,"author":6,"body":7,"caption":259,"cover_image":260,"date":261,"description":16,"extension":262,"meta":263,"navigation":266,"path":267,"seo":268,"stem":269,"__hash__":270},"blog\u002Fblog\u002F25-10-26.md","DEVLOG 2: L'Open Source, dans la peau d’un mainteneur","Baptiste Zahnow",{"type":8,"value":9,"toc":253},"minimark",[10,58,61,64,70,146,149,163,165,197,199,202,205,208,244,247,250],[11,12,13,21],"accordeon",{},[14,15,17],"template",{"v-slot:title":16},"",[18,19,20],"p",{},"Tables des matières",[14,22,23],{"v-slot:details":16},[24,25,26,34,40,46,52],"ul",{},[27,28,29],"li",{},[30,31,33],"a",{"href":32},"#quest-ce-que-le-foss","Qu'est-ce que le FOSS ?",[27,35,36],{},[30,37,39],{"href":38},"#pourquoi-lopen-source","Pourquoi l'Open Source ?",[27,41,42],{},[30,43,45],{"href":44},"#lopen-source-de-linterieur","L'Open Source de l'intérieur",[27,47,48],{},[30,49,51],{"href":50},"#comment-bien-contribuer-a-un-projet-open-source","Comment bien contribuer à un projet Open Source",[27,53,54],{},[30,55,57],{"href":56},"#conclusion","Conclusion",[59,60],"hr",{},[62,63],"br",{},[65,66,67],"quote-block",{},[18,68,69],{},"L’Open Source est une longue partie de ma philosophie de vie. Lorsqu’on crée quelque chose qui règle un de nos problèmes, pourquoi ne pas aider son prochain en lui donnant la solution.",[71,72,80,136],"div",{"className":73},[74,75,76,77,78,79],"grid","grid-cols-2","max-md:grid-cols-1","my-4","gap-4","items-center",[71,81,82,86,130,133],{},[83,84,33],"h2",{"id":85},"quest-ce-que-le-foss",[18,87,88,89,96,97,102,103,108,109,96,114,96,119,102,124,129],{},"FOSS veut dire : Free and Open Source Software, c'est un acronyme pour les applications et les contenus dans la sphère du développement qui sont libre de droit. Des exemples connus de FOSS : ",[30,90,95],{"href":91,"rel":92,"target":94},"https:\u002F\u002Fwww.linux.org\u002F",[93],"nofollow","\\_blank","Linux",", ",[30,98,101],{"href":99,"rel":100,"target":94},"https:\u002F\u002Fpretendo.network\u002F",[93],"Pretendo"," et ",[30,104,107],{"href":105,"rel":106,"target":94},"https:\u002F\u002Fwww.blender.org\u002F",[93],"Blender",". Pour être qualifié de FOSS il faut que n'importe qui puisse avoir accès au code et d'avoir le droit de le modifier et de distribuer sa version. Pour Linux, les \"fork\" (une copie modifiée du code), il y en a un nombre incalculable, mais les plus connus sont ",[30,110,113],{"href":111,"rel":112,"target":94},"https:\u002F\u002Fwww.debian.org\u002F",[93],"Debian",[30,115,118],{"href":116,"rel":117,"target":94},"https:\u002F\u002Fubuntu.com\u002F",[93],"Ubuntu",[30,120,123],{"href":121,"rel":122,"target":94},"https:\u002F\u002Fwww.linuxmint.com\u002F",[93],"Mint",[30,125,128],{"href":126,"rel":127,"target":94},"https:\u002F\u002Farchlinux.org\u002F",[93],"Arch",".",[83,131,39],{"id":132},"pourquoi-lopen-source",[18,134,135],{},"J'adore l'Open Source, ça permet de se connecter avec des gens de plein d'horizons différents et d'avoir des visions différentes ou complémentaires sur des problèmes. Le fait de pouvoir collaborer à plusieurs, peu importe où aide à la conception, comme un hackathon qui ne se finit jamais 24h\u002F24. Des personnes peuvent tomber sur votre projet par hasard et commencer à l'utiliser, ou une personne utilisant déjà votre projet venant avec une nouvelle proposition d'ajout. Le monde de l'Open Source est un monde vivant, richissime en interaction.",[71,137,138],{},[18,139,140,145],{},[141,142],"img",{"alt":143,"src":144},"\"Capture d'écran d'un bureau avec de multiples logiciels libres et open-source en cours d'exécution : notamment VLC media player, Firefox, LibreOffice Writer et GIMP.\"","https:\u002F\u002Fupload.wikimedia.org\u002Fwikipedia\u002Fcommons\u002F2\u002F2a\u002FFedora_Linux_36_takes_pic_with_bunch_of_FOSS_softwares.png?utm_source=fr.wikipedia.org&utm_campaign=imageinfo&utm_content=thumbnail_unscaled","\nImage par Discordpeople — Travail personnel, CC BY-SA 4.0",[83,147,45],{"id":148},"lopen-source-de-lintérieur",[18,150,151,152,157,158,162],{},"Je suis un développeur qui utilise beaucoup de projets Open Source mais aussi qui en crée et qui en a la responsabilité de maintenance. Cela fait maintenant plus de 3 ans que je maintiens un projet du nom de ",[30,153,156],{"href":154,"rel":155},"https:\u002F\u002Fgithub.com\u002FLelouchFR\u002Fskill-icons",[93],"Skill Icons"," (vous pouvez trouver plus d'informations à ce sujet sur ",[30,159,161],{"href":160},"\u002Fprojects\u002Fskill-icons","la page du projet","). Je vais vous expliquer les méthodes que j'ai utilisées pour maintenir le projet et les soucis importants auxquels vous pouvez être confronté.",[62,164],{},[71,166,168,182],{"className":167},[74,75,76,77,78,79],[71,169,173,176,179],{"className":170},[171,172,78],"flex","flex-col",[18,174,175],{},"Le projet sur la durée a bâti une librairie de plus de 830 icônes vectorielles harmonisées, qui peut être utile pour montrer ses compétences dans le monde de la tech, sur GitHub ou sur son CV. La règle numéro une instaurée sur le projet est : 100% vectoriel. Pas d'image pixelisée pour garantir une qualité chirurgicale à l'utilisateur et une possibilité de customisation sans limite.",[18,177,178],{},"L'icône par défaut est une icône qui se modifie elle-même par rapport au thème système utilisé, c'est-à-dire que si vous avez votre navigateur en thème sombre, l'icône va apparaître en thème sombre et si vous êtes en thème clair, l'icône va apparaître en thème clair. Une simple fonctionnalité utilisant du CSS dans un SVG, mais la plupart des contributeurs ne regardent pas comment ça marche et ajoutent dans le thème auto l'icône qu'ils voient s'afficher dans leur navigateur.",[18,180,181],{},"Je leur demande à tous de devoir ouvrir une icône random en auto pour comprendre comment ça marche, mais le problème est que personne ne lit les anciennes issues et pull requests et le CONTRIBUTING.md, qui sont des choses très importantes dans un projet Open Source. Je finis par devoir toujours réexpliquer que ce fichier existe, qu'il faut un peu regarder l'historique du projet et regarder les choses qui l'entourent.",[71,183,186,192],{"className":184},[171,172,78,185],"relative",[187,188],"diff-slider",{"after-image":189,"before-image":190,"id":191},"https:\u002F\u002Fraw.githubusercontent.com\u002FLelouchFR\u002FLelouchFR\u002Fa3e1007c29948ef6d5c8d4f22633ab52d71b8740\u002Fcontent\u002Ftechnologies.svg","https:\u002F\u002Fgo-skill-icons.vercel.app\u002Fapi\u002Ficons?i=nuxtjs,vuejs,tailwindcss,wordpress,react,nodejs,symfony,laravel,htmx&perline=5","skillicons",[65,193,194],{},[18,195,196],{},"Pour avoir réussi à maintenir cette grande librairie d'icônes, j'ai travaillé avec une trentaine de personnes qui m'ont aidé au long de ces 3 ans.",[62,198],{},[18,200,201],{},"Ce qu’il faut comprendre pour l’Open Source c’est que ce sont souvent des projets de passionnés qui sont là pour aider un maximum de gens, mais cela peut vite se transformer sans que les contributeurs le sachent en une forme de fatigue du projet à cause des évènements survenant dans le projet. Ce que je veux dire par là c’est une fatigue des demandes à répétition de choses qui sont peut-être déjà faites ou des demandes sans prendre en compte des issues qui ont parlé du sujet, les gens ne prennent aucun temps à regarder l’existant.",[18,203,204],{},"Une chose aussi en parlant de fatigue est que l’on reçoit très peu de soutien moral sur le maintien du projet. On vient très souvent vers nous en parlant des problèmes de l’un et de l’autre, mais il est très rare d'avoir du soutien pour le travail déjà effectué. Ouvrir une issue est une action simple, mais en ayant le contexte du projet et les connaissances sur le système, il est très simple de pouvoir apporter sa pierre à l’édifice et d’apporter une bonne ambiance dans un projet Open Source.",[83,206,51],{"id":207},"comment-bien-contribuer-à-un-projet-open-source",[71,209,212,227],{"className":210},[74,75,76,77,78,211],"items-start",[71,213,215,218,221,224],{"className":214},[171,172,78],[18,216,217],{},"Pour contribuer à un projet Open Source, il y a eu plusieurs facteurs à prendre en compte : l’âge du projet, l’historique du projet, c’est-à-dire les pull-requests et les issues qui ont fait le plus de bruit dans le projet, mais aussi les fichiers dédiés à l’aide pour la contribution.",[18,219,220],{},"Plus un projet a de l’âge, plus il aura de conseils sur la création ou le maintien propre de celui-ci. Des règles sur comment il faut écrire certaines parties du code, comment nommer la pull request, comme écrire ses commits, plein d'éléments qui peuvent différer d’un projet à un autre mais qu’il est important de respecter.",[18,222,223],{},"L’historique du projet est très important, ça sert à pouvoir comprendre comment fonctionne le projet, les sujets qui ont déjà été abordés et le pourquoi du comment les choses sont faites comme elles sont dans le projet.",[18,225,226],{},"Soutenir les projets Open Source donne beaucoup de force aux contributeurs et surtout aux mainteneurs, et ne peut que faire du bien. Pensez-y.",[71,228,230,236],{"className":229},[171,172,78],[18,231,232],{},[141,233],{"alt":234,"src":235},"\"Pretendo tasks and goals\"","\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fpretendo_tasks_and_goals.png",[65,237,238],{},[18,239,240,243],{},[30,241,101],{"href":99,"rel":242,"target":94},[93]," est un projet auquels je donne beaucoup de soutien et auquels je contribue fréquemment.",[83,245,57],{"id":246},"conclusion",[18,248,249],{},"Si vous voulez contribuer à un projet Open Source, prenez un projet qui parle d’un sujet qui vous tient à cœur. Faire de simples fix de grammaires dans un projet n’est pas une contribution intéressante. Vous pouvez faire une issue pour, mais une pull request pour ce genre de problème est contre-productif. Prenez un projet qui vous aide à régler un souci qui vous turlupine ou un outil que vous connaissez, que vous utilisez. Savoir comment utiliser un outil aide énormément à la création autour de celui-ci.",[18,251,252],{},"J'espère vous avoir appris des choses sur le monde de l’Open Source et que cela pourra vous être utile si vous voulez en faire. Un monde sans partage d'idées ne peut pas avancer.",{"title":16,"searchDepth":254,"depth":254,"links":255},2,[256,257,258],{"id":148,"depth":254,"text":45},{"id":207,"depth":254,"text":51},{"id":246,"depth":254,"text":57},"Qu'est-ce que l'Open Source ? Comment ça marche ? Comment contribuer ? Je réponds à ces questions en tant que mainteneur de projets libre de droit.","\u002Fassets\u002Fimages\u002Fblogposts\u002F25-10-26.png","25\u002F10\u002F2026 9:37","md",{"sitemap":264},{"lastmod":265},"2026-10-25",true,"\u002Fblog\u002F25-10-26",{"title":5,"description":16},"blog\u002F25-10-26","Gt6ODo8INMPfqd4DKBAtv9Lk9EJ8oSYxq8nQ6FhkXiY",[272,276],{"title":273,"path":274,"stem":275,"description":16,"children":-1},"Est-ce possible de changer la couleur du château de Duras depuis le terminal ?","\u002Fblog\u002F24-12-25","blog\u002F24-12-25",null,[278,333,470,1025,2535],{"id":279,"title":280,"author":6,"body":281,"caption":324,"cover_image":320,"date":325,"description":16,"extension":262,"meta":326,"navigation":266,"path":329,"seo":330,"stem":331,"__hash__":332},"blog\u002Fblog\u002F04-03-26.md","DEVLOG 1: Mise en ligne de mon portfolio",{"type":8,"value":282,"toc":322},[283],[71,284,286,287,316],{"className":285},[74,75,76,77,78,211],"\n    ",[71,288,290,291,290,296,290,300,290,304,290,308,286],{"className":289},[171,172,78],"\n        ",[18,292,295],{"className":293},[294],"block","Bonjour tout le monde, j'ai le plaisir de vous annoncer que mon portfolio est ouvert pour ce premier devlog 🥳 !",[18,297,299],{"className":298},[294],"J'ai travaillé sur la refonte de mon site internet depuis décembre 2025. Aujourd'hui mon site est prêt à être mis en production. Chaque composant a été pensé et évalué pour une expérience fluide. Entre l'optimisation des médias, les commentaires sous les posts de blogs et le déploiement, j'ai acquis énormément de savoir sur la création de site pour un internet meilleur.",[18,301,303],{"className":302},[294],"Un site internet peut prendre du temps à créer, car derrière tout cela il n'y a pas que du code, il y a une longue période de réflexion, de conception technique et graphique. J'optimise mon workflow pour avoir une conception qui suit les retours des clients et une mise en place d'un calendrier pour être efficace.",[18,305,307],{"className":306},[294],"Si vous avez quelques questions, vous pouvez les poser dans la section commentaires de ce premier devlog d'une longue série à venir. Que ce soit des sujets pour des prochains devlogs ou simplement des questions que l'on peut se poser sur la création de site internet, tout sujet est le bienvenu !",[18,309,311,312,129],{"className":310},[294],"Je suis aussi ouvert pour mettre à profit mes compétences si vous avez un projet en tête. Vous pouvez me faire une demande sur mon ",[30,313,315],{"href":314},"\u002Fcontact","formulaire de contact",[317,318],"video-player",{":controls":319,":loop":319,"poster":320,"src":321},"true","\u002Fassets\u002Fimages\u002Fblogposts\u002F04-03-26.png","\u002Fassets\u002Fvideos\u002Fblogposts\u002Fcontent\u002Fportfolio_motion.mp4",{"title":16,"searchDepth":254,"depth":254,"links":323},[],"Mon portfolio est en ligne! Des mois de réflexion, de design et d'optimisation pour vous proposer une expérience fluide et moderne.","04\u002F03\u002F2026 11:24",{"sitemap":327},{"lastmod":328},"2026-03-04","\u002Fblog\u002F04-03-26",{"title":280,"description":16},"blog\u002F04-03-26","ym3ogAnAsqf2Cuf38uRjwliRQmM0cKOoGc58gNMX3-Q",{"id":334,"title":335,"author":6,"body":336,"caption":460,"cover_image":461,"date":462,"description":16,"extension":262,"meta":463,"navigation":266,"path":466,"seo":467,"stem":468,"__hash__":469},"blog\u002Fblog\u002F13-02-26.md","Les langages de programmation les plus utilisés en 2025",{"type":8,"value":337,"toc":454},[338,372,374,377,380,383,387,415,418,438,441,444,446,449,451],[11,339,340,344],{},[14,341,342],{"v-slot:title":16},[18,343,20],{},[14,345,346],{"v-slot:details":16},[24,347,348,354,360,366],{},[27,349,350],{},[30,351,353],{"href":352},"#que-sest-t-il-pass%C3%A9-en-2025","Que s'est-t-il passé en 2025 ?",[27,355,356],{},[30,357,359],{"href":358},"#les-languages-qui-ont-%C3%A9t%C3%A9-en-vogue","Les languages qui été en vogue",[27,361,362],{},[30,363,365],{"href":364},"#en-terme-de-s%C3%A9curit%C3%A9","En terme de sécurité ?",[27,367,368],{},[30,369,371],{"href":370},"#%C3%A0-quoi-sattendre-pour-2026","À quoi s'attendre pour 2026",[59,373],{},[83,375,353],{"id":376},"que-sest-t-il-passé-en-2025",[18,378,379],{},"Cette année 2025 a eu beaucoup de bousculades en termes de programmation, de nouveaux outils font leur apparition, mais aussi les langages les plus utilisés qui le deviennent encore plus.\nUne nouvelle année avec de nouveaux frameworks et de nouvelles mises à jour importantes sur des librairies. Énormément de failles de sécurité ont été découvertes sur de larges codebases.",[18,381,382],{},"Aujourd'hui, avec du recul, nous allons faire un petit point sur les moments clés de cette année 2025.",[83,384,386],{"id":385},"les-languages-qui-ont-été-en-vogue","Les languages qui ont été en vogue",[71,388,286,390,286,411],{"className":389},[74,75,76,77,78],[71,391,290,394,290,402,290,405,290,408,286],{"className":392},[171,172,393],"gap-3",[18,395,396,397,401],{},"L'année 2025 est celle de ",[398,399,400],"strong",{},"TypeScript",", car elle est implémentée dans la plupart des nouveaux projets qui sont créés car il aide à pouvoir trouver des erreurs de types plus rapidement que du JavaScript. Il est utilisé dans plusieurs domaines, surtout dans celui du développement web. TypeScript a décidé d'interchanger sa place avec son frère JavaScript.",[18,403,404],{},"Python est aussi un langage incontournable depuis des années, mais surtout en ce moment à cause de la création des Large Language Models et du Machine Learning. Un simple langage de script qui peut contribuer à la visualisation d'énormément de données et à la création de beaucoup d'outils.",[18,406,407],{},"Java, C# et PHP restent des langages très utilisés pour le côté serveur et restent stables à leur position attitrée.",[18,409,410],{},"Un nouveau venu fait son apparition dans le top des langages, le HCL, un langage de script pour la modélisation de données. Il aide à générer dynamiquement des fichiers de données tels que le JSON.",[141,412],{"src":413,"alt":414},"https:\u002F\u002Fgithub.blog\u002Fwp-content\u002Fuploads\u002F2025\u002F10\u002Foctoverse-2025-top-programming-languages.png?w=1024","Les languages les plus utilisé",[83,416,365],{"id":417},"en-terme-de-sécurité",[71,419,286,421,286,424],{"className":420},[74,75,76,77,78],[141,422],{"src":423,"alt":414},"https:\u002F\u002Fgithub.blog\u002Fwp-content\u002Fuploads\u002F2025\u002F10\u002Foctoverse-2025-most-common-vulnerability-types-codeql.png?w=1024",[71,425,290,427,290,435,286],{"className":426},[171,172,393],[18,428,429,430,434],{},"L'année 2025 a été marquée par une forte hausse des attaques liées aux défaillances de contrôle d'accès, devenues l'un des principaux vecteurs de fuites massives de données via des API mal sécurisées et des systèmes d'authentification mal configurés. Les vulnérabilités dans des composants obsolètes ont également eu un impact majeur, avec l'exploitation active de failles critiques comme ",[30,431,433],{"href":432},"\u002Fblog\u002F15-12-25","React2Shell",", permettant l'exécution de commandes à distance sur des applications insufisamment protégées.",[18,436,437],{},"Parallèlement, les attaques visant la chaîne d'approvisionnement logicielle et les environnements cloud se sont intensifiées, notamment par la compromission de dépendances et de mécanismes de mise à jour, exposant des millions d'identifiants et de données sensibles à travers le monde.",[83,439,371],{"id":440},"à-quoi-sattendre-pour-2026",[18,442,443],{},"L'année 2026 devrait s'inscrire dans la continuité directe de 2025, avec une accélération encore plus marquée autour des outils modernes. TypeScript devrait continuer de dominer le développement web, tandis que Python restera au coeur des projets liés aux LLM, à la data et à l'automatisation. Les frameworks évolueront rapidement, avec des mises à jour toujours plus fréquentes pour avoir le meilleur de la technologies et de la sécurité.",[62,445],{},[18,447,448],{},"Côté sécurité, la tendance laisse présager une augmentation des attaques ciblant les architectures cloud, les API et les chaînes d'approvisionnement logicielle. Les dépendances resteront un point sensible, obligeant les équipes à renforcer la gestion des versions et la surveillance des vulnérabilités.",[62,450],{},[18,452,453],{},"2026 pourrait marquer un tournant dans la manière de concevoir les applications. La sécurité ne sera plus seulement une étape finale, mais devra être intégrée dès la phase de conception. Les développeurs devront composer avec des environnements toujours plus puissants.",{"title":16,"searchDepth":254,"depth":254,"links":455},[456,457,458,459],{"id":376,"depth":254,"text":353},{"id":385,"depth":254,"text":386},{"id":417,"depth":254,"text":365},{"id":440,"depth":254,"text":371},"Petit récap sur l'année 2025 en terme de langages de programmation et des technologies qui ont été en vogue cette année.","\u002Fassets\u002Fimages\u002Fblogposts\u002F13-02-26.png","13\u002F02\u002F2026 09:32",{"sitemap":464},{"lastmod":465},"2026-02-13","\u002Fblog\u002F13-02-26",{"title":335,"description":16},"blog\u002F13-02-26","70ccCe3UoKhusrst-JUxnaDOKYe0Fp4R9c1nxpd9nLM",{"id":471,"title":472,"author":6,"body":473,"caption":1016,"cover_image":1017,"date":1018,"description":16,"extension":262,"meta":1019,"navigation":266,"path":432,"seo":1022,"stem":1023,"__hash__":1024},"blog\u002Fblog\u002F15-12-25.md","React2Shell: la faille critique qui permet de prendre le contrôle d'un serveur React",{"type":8,"value":474,"toc":1003},[475,546,548,552,574,577,580,583,594,598,601,612,615,620,623,853,910,919,922,948,951,956,959,967,970,974,982,986,994,996,999],[11,476,477,481],{},[14,478,479],{"v-slot:title":16},[18,480,20],{},[14,482,483],{"v-slot:details":16},[24,484,485,491,497,503,509,515,542],{},[27,486,487],{},[30,488,490],{"href":489},"#quest-ce-que-react2shell","Qu'est-ce que React2Shell",[27,492,493],{},[30,494,496],{"href":495},"#contexte-technique","Contexte technique",[27,498,499],{},[30,500,502],{"href":501},"#comment-lexploit-fonctionne","Comment l'exploit fonctionne",[27,504,505],{},[30,506,508],{"href":507},"#exemple-de-payload-poc-proof-of-concept","Exemple de Payload \u002F PoC (Proof of Concept)",[27,510,511],{},[30,512,514],{"href":513},"#exemples-dexploits-observ%C3%A9s-dans-la-nature","Exemples d’exploits observés dans la nature",[27,516,517,521],{},[30,518,520],{"href":519},"#comment-se-prot%C3%A9ger","Comment se protéger",[522,523,524,530,536],"ol",{},[27,525,526],{},[30,527,529],{"href":528},"#appliquer-imm%C3%A9diatement-les-correctifs","appliquer immédiatement les correctifs",[27,531,532],{},[30,533,535],{"href":534},"#d%C3%A9ployer-des-protections-temporaires","Déployer des protections temporaires",[27,537,538],{},[30,539,541],{"href":540},"#surveillance-et-r%C3%A9ponse","Surveillance et réponse",[27,543,544],{},[30,545,57],{"href":56},[59,547],{},[83,549,551],{"id":550},"quest-ce-que-react2shell","Qu'est-ce que React2Shell ?",[18,553,554,555,558,559,562,563,570,571,129],{},"La faille ",[556,557,433],"em",{}," correspond à une ",[398,560,561],{},"vulnérabilité critique de type Remote Code Execution (RCE)"," dans l’écosystème React Server Components (RSC), exploitée sans authentification par de nombreux attaquants dès sa publication en décembre 2025. Elle est suivie sous l’identifiant ",[398,564,565],{},[30,566,569],{"href":567,"rel":568},"https:\u002F\u002Fnvd.nist.gov\u002Fvuln\u002Fdetail\u002FCVE-2025-55182",[93],"CVE-2025-55182"," et porte une note ",[398,572,573],{},"CVSS de 10.0 (maximum)",[83,575,496],{"id":576},"contexte-technique",[18,578,579],{},"React Server Components (RSC) utilisent un protocole interne appelé Flight, permettant au serveur de recevoir et désérialiser des données complexes envoyées par le client. La faille survient lorsque le serveur désérialise ces données sans les valider correctement, ce qui ouvre la porte à une exploitation par des données malicieuses.",[18,581,582],{},"Pourquoi c'est grave ?",[24,584,585,588,591],{},[27,586,587],{},"Exécution de code à distance (RCE) dès une simple requête HTTP, sans authentification.",[27,589,590],{},"Affecte de nombreuses applications modernes utilisant RSC, notamment celles construites avec Next.js ou intégrant des bundlers comme Parcel\u002FVite.",[27,592,593],{},"Exploitation observée dans la nature par des groupes étatiques et des cybercriminels.",[83,595,597],{"id":596},"comment-lexploit-fonctionne","Comment l’exploit fonctionne",[18,599,600],{},"L’attaque repose sur une désérialisation non sécurisée : l’attaquant envoie un objet JSON construit spécialement qui, au lieu d’être interprété comme des données, contourne les contrôles internes et permet d’injecter du code exécuté par le serveur.",[522,602,603,606,609],{},[27,604,605],{},"Cible un endpoint acceptant des payloads RSC (Next.js App Router ou RSC sans authentification).",[27,607,608],{},"Envoie un payload mal formé manipulant le prototype d’objets ou les structures internes de React.",[27,610,611],{},"Lors de la désérialisation, React exécute du code arbitraire contrôlé par l’attaquant.",[83,613,508],{"id":614},"exemple-de-payload-poc-proof-of-concept",[65,616,617],{},[18,618,619],{},"À ne pas utiliser sur des systèmes que tu ne possèdes pas ou n'as pas la permission de tester - exploitation non autorisée = illégale.",[18,621,622],{},"Voici un extrait de payload réel observé dans un PoC, utilisé pour démontrer l’exploitation. Il montre comment une requête multipart peut déclencher une commande sur le serveur :",[624,625,628],"code-block",{"filename":626,"filetype":627},"payload.js","javascript",[14,629,630],{"v-slot:code":16},[631,632,636],"pre",{"className":633,"code":634,"language":635,"meta":16,"style":16},"language-js shiki shiki-themes everforest-light","const payload = {\n    '0': '$1',\n    '1': {\n        'status': 'resolved_model',\n        'reason': 0,\n        '_response': '$4',\n        'value': '{\"then\":\"$3:map\",\"0\":{\"then\":\"$B3\"},\"length\":1}',\n        'then': '$2:then'\n    },\n    '2': '$@3',\n    '3': [],\n    '4': {\n        '_prefix': 'process.mainModule.require(\"child_process\").execSync(\"touch \u002Ftmp\u002Frce_poc\");',\n        '_formData': {\n            'get': '$3:constructor:constructor'\n        },\n        '_chunks': '$2:_response:_chunks',\n    }\n};\n","js",[637,638,639,658,674,684,697,711,724,737,748,754,767,778,788,801,811,822,828,841,847],"code",{"__ignoreMap":16},[640,641,644,648,652,655],"span",{"class":642,"line":643},"line",1,[640,645,647],{"class":646},"sWOlJ","const",[640,649,651],{"class":650},"sNieu"," payload ",[640,653,654],{"class":646},"=",[640,656,657],{"class":650}," {\n",[640,659,660,664,668,671],{"class":642,"line":254},[640,661,663],{"class":662},"soamM","    '0'",[640,665,667],{"class":666},"sMLMF",":",[640,669,670],{"class":662}," '$1'",[640,672,673],{"class":650},",\n",[640,675,677,680,682],{"class":642,"line":676},3,[640,678,679],{"class":662},"    '1'",[640,681,667],{"class":666},[640,683,657],{"class":650},[640,685,687,690,692,695],{"class":642,"line":686},4,[640,688,689],{"class":662},"        'status'",[640,691,667],{"class":666},[640,693,694],{"class":662}," 'resolved_model'",[640,696,673],{"class":650},[640,698,700,703,705,709],{"class":642,"line":699},5,[640,701,702],{"class":662},"        'reason'",[640,704,667],{"class":666},[640,706,708],{"class":707},"sFsDM"," 0",[640,710,673],{"class":650},[640,712,714,717,719,722],{"class":642,"line":713},6,[640,715,716],{"class":662},"        '_response'",[640,718,667],{"class":666},[640,720,721],{"class":662}," '$4'",[640,723,673],{"class":650},[640,725,727,730,732,735],{"class":642,"line":726},7,[640,728,729],{"class":662},"        'value'",[640,731,667],{"class":666},[640,733,734],{"class":662}," '{\"then\":\"$3:map\",\"0\":{\"then\":\"$B3\"},\"length\":1}'",[640,736,673],{"class":650},[640,738,740,743,745],{"class":642,"line":739},8,[640,741,742],{"class":662},"        'then'",[640,744,667],{"class":666},[640,746,747],{"class":662}," '$2:then'\n",[640,749,751],{"class":642,"line":750},9,[640,752,753],{"class":650},"    },\n",[640,755,757,760,762,765],{"class":642,"line":756},10,[640,758,759],{"class":662},"    '2'",[640,761,667],{"class":666},[640,763,764],{"class":662}," '$@3'",[640,766,673],{"class":650},[640,768,770,773,775],{"class":642,"line":769},11,[640,771,772],{"class":662},"    '3'",[640,774,667],{"class":666},[640,776,777],{"class":650}," [],\n",[640,779,781,784,786],{"class":642,"line":780},12,[640,782,783],{"class":662},"    '4'",[640,785,667],{"class":666},[640,787,657],{"class":650},[640,789,791,794,796,799],{"class":642,"line":790},13,[640,792,793],{"class":662},"        '_prefix'",[640,795,667],{"class":666},[640,797,798],{"class":662}," 'process.mainModule.require(\"child_process\").execSync(\"touch \u002Ftmp\u002Frce_poc\");'",[640,800,673],{"class":650},[640,802,804,807,809],{"class":642,"line":803},14,[640,805,806],{"class":662},"        '_formData'",[640,808,667],{"class":666},[640,810,657],{"class":650},[640,812,814,817,819],{"class":642,"line":813},15,[640,815,816],{"class":662},"            'get'",[640,818,667],{"class":666},[640,820,821],{"class":662}," '$3:constructor:constructor'\n",[640,823,825],{"class":642,"line":824},16,[640,826,827],{"class":650},"        },\n",[640,829,831,834,836,839],{"class":642,"line":830},17,[640,832,833],{"class":662},"        '_chunks'",[640,835,667],{"class":666},[640,837,838],{"class":662}," '$2:_response:_chunks'",[640,840,673],{"class":650},[640,842,844],{"class":642,"line":843},18,[640,845,846],{"class":650},"    }\n",[640,848,850],{"class":642,"line":849},19,[640,851,852],{"class":650},"};\n",[71,854,286,856,286,906],{"className":855},[74,75,76,77,79],[18,857,858,859,96,862,102,865,868,869,872,873,876,877,129,880,882,884,885,888,889,892,893,896,897,899,901,902,905],{},"Pendant la désérialisation, les références d'objets telles que ",[637,860,861],{},"$1",[637,863,864],{},"$3",[637,866,867],{},"$4"," sont résolues de manière dynamique. L'attaquant injecte un objet de réponse conçu contenant une chaîne de code malveillant dans un champ ",[637,870,871],{},"_prefix"," et manipule ",[637,874,875],{},"_formData.get"," pour le résoudre en ",[637,878,879],{},"$3:constructor:constructor",[62,881],{},[62,883],{},"\n    En JavaScript, l'accès à ",[637,886,887],{},"constructor.constructor"," aboutit finalement au constructeur ",[637,890,891],{},"Function",", qui permet l'exécution dynamique de code. En abusant également d'une propriété ",[637,894,895],{},"then"," pour déclencher le mécanisme de résolution des promesses de React, la charge utile amène le runtime à évaluer le code injecté.",[62,898],{},[62,900],{},"\n    Cela entraîne l'exécution d'une commande shell via ",[637,903,904],{},"child_process.execSync"," de Node.js, permettant ainsi l'exécution de code à distance.",[141,907],{"src":908,"alt":909},"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fr2s_explanation.png","Eplanation of the PoC",[18,911,912,913,918],{},"Il s’agit du principe utilisé par de nombreux PoCs sur des dépôts publics (ex. ",[30,914,917],{"href":915,"rel":916},"https:\u002F\u002Fgithub.com\u002Fzr0n\u002Freact2shell",[93],"zr0n\u002Freact2shell"," PoC sur GitHub).",[83,920,514],{"id":921},"exemples-dexploits-observés-dans-la-nature",[71,923,286,925,286,945],{"className":924},[74,75,76,77,79],[71,926,290,927,290,930,286],{},[18,928,929],{},"Après la publication des PoC, différents types d’exploits ont été observés via cette vulnérabilité :",[24,931,932,933,932,936,932,939,932,942,290],{},"\n            ",[27,934,935],{},"Reverse shells et commandes arbitraires sur les serveurs Node.js.",[27,937,938],{},"Téléchargement de scripts malveillants (via curl, wget) pour installer des backdoors ou cryptominers.",[27,940,941],{},"Déploiement de malware sophistiqués comme EtherRAT avec persistance Linux et C2 via les smart contracts Ethereum.",[27,943,944],{},"Campagnes d’exploitation par des groupes APT (Earth Lamia, Jackpot Panda, etc.) et par des équipes criminelles pour miner de la cryptomonnaie ou voler des données.",[141,946],{"src":947,"alt":16},"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fr2s_graph.png",[83,949,520],{"id":950},"comment-se-protéger",[952,953,955],"h3",{"id":954},"_1-appliquer-immédiatement-les-correctifs","1. Appliquer immédiatement les correctifs",[18,957,958],{},"React et Next.js ont publié des versions corrigées :",[24,960,961,964],{},[27,962,963],{},"React Server Components : ≥ 19.0.1, 19.1.2, 19.2.1",[27,965,966],{},"Next.js : versions stables corrigées disponibles (ex. 15.0.5+, 16.0.7+)",[18,968,969],{},"Mettre à jour tous les composants vulnérables est essentiel.",[952,971,973],{"id":972},"_2-déployer-des-protections-temporaires","2. Déployer des protections temporaires",[24,975,976,979],{},[27,977,978],{},"Utiliser un WAF (Web Application Firewall) avec des règles bloquant les vecteurs d’exploit.",[27,980,981],{},"Limiter l’exposition publique des endpoints RSC.",[952,983,985],{"id":984},"_3-surveillance-et-réponse","3. Surveillance et réponse",[24,987,988,991],{},[27,989,990],{},"Rechercher des requêtes HTTP suspectes avec des champs anormaux (multipart\u002Fform-data contenant des clés inattendues).",[27,992,993],{},"Auditer les logs pour commandes exécutées, fichiers créés ou shells ouverts.",[83,995,57],{"id":246},[18,997,998],{},"La faille React2Shell est une des vulnérabilités les plus sévères et impactantes découvertes récemment dans l’écosystème JavaScript. Grâce à une erreur de désérialisation dans React Server Components, des attaquants peuvent exécuter du code arbitraire sur des serveurs, sans authentification, avec des conséquences potentiellement dévastatrices pour les applications et les infrastructures exposées.",[1000,1001,1002],"style",{},"html pre.shiki code .sWOlJ, html code.shiki .sWOlJ{--shiki-default:#F57D26}html pre.shiki code .sNieu, html code.shiki .sNieu{--shiki-default:#5C6A72}html pre.shiki code .soamM, html code.shiki .soamM{--shiki-default:#DFA000}html pre.shiki code .sMLMF, html code.shiki .sMLMF{--shiki-default:#939F91}html pre.shiki code .sFsDM, html code.shiki .sFsDM{--shiki-default:#DF69BA}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}",{"title":16,"searchDepth":254,"depth":254,"links":1004},[1005,1006,1007,1008,1009,1010,1015],{"id":550,"depth":254,"text":551},{"id":576,"depth":254,"text":496},{"id":596,"depth":254,"text":597},{"id":614,"depth":254,"text":508},{"id":921,"depth":254,"text":514},{"id":950,"depth":254,"text":520,"children":1011},[1012,1013,1014],{"id":954,"depth":676,"text":955},{"id":972,"depth":676,"text":973},{"id":984,"depth":676,"text":985},{"id":246,"depth":254,"text":57},"Quand la désérialisation de React ouvre la porte à une prise de contrôle totale du serveur","\u002Fassets\u002Fimages\u002Fblogposts\u002F15-12-25.png","15\u002F12\u002F2025 17:12",{"sitemap":1020},{"lastmod":1021},"2025-12-15",{"title":472,"description":16},"blog\u002F15-12-25","RPK6puycRqGnWIC2l3NZNpGGU5OegJyZDItXlanRyS0",{"id":1026,"title":273,"author":6,"body":1027,"caption":2528,"cover_image":2506,"date":2529,"description":16,"extension":262,"meta":2530,"navigation":266,"path":274,"seo":2533,"stem":275,"__hash__":2534},"blog\u002Fblog\u002F24-12-25.md",{"type":8,"value":1028,"toc":2520},[1029,1057,1059,1062,1065,1068,1082,1093,1217,1221,1269,1272,1282,1285,1385,1388,1391,1539,1542,1657,1660,2221,2224,2234,2237,2243,2254,2261,2458,2482,2486,2508,2517],[11,1030,1031,1035],{},[14,1032,1033],{"v-slot:title":16},[18,1034,20],{},[14,1036,1037],{"v-slot:details":16},[24,1038,1039,1045,1051],{},[27,1040,1041],{},[30,1042,1044],{"href":1043},"#brainstorm","Brainstorm",[27,1046,1047],{},[30,1048,1050],{"href":1049},"#poc-proof-of-concept","PoC (Proof of Concept)",[27,1052,1053],{},[30,1054,1056],{"href":1055},"#cr%C3%A9ation-du-cli","Création du CLI",[59,1058],{},[83,1060,1044],{"id":1061},"brainstorm",[18,1063,1064],{},"J'ai eu cette idée quand je suis passé devant le château de Duras, lors des vacances d'hiver. Je savais déjà qu'il existait un site officiel mis en place pour changer les couleurs du château, mais je n'avais pas l'oeil technique à ce moment là. J'ai décidé de me lancer dans la recherche sur comment le site fonctionne et comment pouvoir mettre ce système à mon profis en créent un CLI pour changer la couleur du château depuis mon terminal. Rendons-nous sur le site internet.",[18,1066,1067],{},"Appuions sur la couleur rouge et voyons ce qu'il en sort:",[624,1069,1072],{"filename":1070,"filetype":1071},"link","bash",[14,1073,1074],{"v-slot:code":16},[631,1075,1080],{"className":1076,"code":1078,"language":1079},[1077],"language-text","https:\u002F\u002Fwww.duras.mobi\u002Fcouleurs.php?ra=0&ran0=1&ran5=254&ran6=0&ran7=0&ran8=&ran9=0\n","text",[637,1081,1078],{"__ignoreMap":16},[18,1083,1084,1085,1088,1089,1092],{},"On finis avec plusieurs valeurs dans une requête ",[637,1086,1087],{},"GET"," sur le fichier ",[637,1090,1091],{},"couleur.php",". Beaucoups de variables sont mise en place lorsque l'on appuie sur la couleur rouge.",[1094,1095,1096,1112],"table",{},[1097,1098,1099],"thead",{},[1100,1101,1102,1106,1109],"tr",{},[1103,1104,1105],"th",{},"Nom",[1103,1107,1108],{},"Valeur",[1103,1110,1111],{},"Description",[1113,1114,1115,1131,1146,1161,1175,1189,1203],"tbody",{},[1100,1116,1117,1123,1128],{},[1118,1119,1120],"td",{},[637,1121,1122],{},"ra",[1118,1124,1125],{},[637,1126,1127],{},"0",[1118,1129,1130],{},"On ne sais pas vraiment çe que ça veux dire",[1100,1132,1133,1138,1143],{},[1118,1134,1135],{},[637,1136,1137],{},"ran0",[1118,1139,1140],{},[637,1141,1142],{},"1",[1118,1144,1145],{},"Surement le mode de couleurs à envoyer",[1100,1147,1148,1153,1158],{},[1118,1149,1150],{},[637,1151,1152],{},"ran5",[1118,1154,1155],{},[637,1156,1157],{},"254",[1118,1159,1160],{},"Le canal rouge du projecteur",[1100,1162,1163,1168,1172],{},[1118,1164,1165],{},[637,1166,1167],{},"ran6",[1118,1169,1170],{},[637,1171,1127],{},[1118,1173,1174],{},"Le canal vert du projecteur",[1100,1176,1177,1182,1186],{},[1118,1178,1179],{},[637,1180,1181],{},"ran7",[1118,1183,1184],{},[637,1185,1127],{},[1118,1187,1188],{},"Le canal bleu du projecteur",[1100,1190,1191,1196,1200],{},[1118,1192,1193],{},[637,1194,1195],{},"ran8",[1118,1197,1198],{},[637,1199,1127],{},[1118,1201,1202],{},"Le canal blanc du projecteur",[1100,1204,1205,1210,1214],{},[1118,1206,1207],{},[637,1208,1209],{},"ran9",[1118,1211,1212],{},[637,1213,1127],{},[1118,1215,1216],{},"Le canal ambre du projecteur",[952,1218,1220],{"id":1219},"comment-est-ce-que-je-peux-être-sur-que-cela-sont-les-canaux-rouge-vert-bleu-blanc-ambre-du-projecteur","Comment est-ce que je peux être sur que cela sont les canaux rouge, vert, bleu, blanc, ambre du projecteur ?",[71,1222,286,1224,286,1265],{"className":1223},[74,75,76,77,78,79],[71,1225,290,1226,1229,290,1231,290,1238,286],{},[18,1227,1228],{},"Le site internet à aussi une page pour pouvoir créer ses propre couleurs. Sur celle-ci on vois les plusieurs champs qui sont disponible pour la création des couleurs, dont: rouge, vert, bleu, blanc, ambre. Ce format de couleurs est très connu pour les projecteurs de lumières.",[62,1230],{},[18,1232,1233,1234,1237],{},"Mais lors de la création d'une couleurs ",[637,1235,1236],{},"RGBWA",", disons par exemple:",[24,1239,932,1240,932,1245,932,1250,932,1255,932,1260,290],{},[27,1241,1242],{},[637,1243,1244],{},"r = 255",[27,1246,1247],{},[637,1248,1249],{},"g = 125",[27,1251,1252],{},[637,1253,1254],{},"b = 0",[27,1256,1257],{},[637,1258,1259],{},"w = 132",[27,1261,1262],{},[637,1263,1264],{},"a = 75",[141,1266],{"src":1267,"alt":1268},"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fsite_duras_color.png","image des canaux disponible sur le site",[18,1270,1271],{},"dans la requête faites pour envoyer les couleurs, on retrouve plusieurs canaux, qui peux faire penser que l'on peux changer la couleurs pour chaque projecteurs différent.",[624,1273,1274],{"filename":1070,"filetype":1071},[14,1275,1276],{"v-slot:code":16},[631,1277,1280],{"className":1278,"code":1279,"language":1079},[1077],"https:\u002F\u002Fwww.duras.mobi\u002F\u002Fcouleur.php?ran0=1&=&ran1=255&ran2=&ran3=&ran4=&ran5=255&ran6=125&ran7=0&ran8=132&ran9=75&ran10=255&ran11=125&ran12=0&ran13=132&ran14=75&ran15=255&ran16=125&ran17=0&ran18=132&ran19=75&ran20=255&ran21=125&ran22=0&ran23=132&ran24=100&ran25=255&ran26=125&ran27=0&ran28=132&ran29=75\n",[637,1281,1279],{"__ignoreMap":16},[18,1283,1284],{},"J'ai rechercher comment je pourrais les regrouper et j'ai trouvé une façon plutôt cohérente:",[71,1286,1288,1372],{"className":1287},[74,75,76,77,78],[1094,1289,1290,1299],{},[1097,1291,1292],{},[1100,1293,1294,1297],{},[1103,1295,1296],{},"Noms",[1103,1298,1111],{},[1113,1300,1301,1311,1324,1336,1348,1360],{},[1100,1302,1303,1308],{},[1118,1304,1305],{},[637,1306,1307],{},"ran0..ran4",[1118,1309,1310],{},"Les champs d'option pour les projecteurs, par exemple la fonction utilisé et l'intensité",[1100,1312,1313,1318],{},[1118,1314,1315],{},[637,1316,1317],{},"ran5..ran9",[1118,1319,1320,1321,1323],{},"Les canaux ",[637,1322,1236],{}," pour le premier projecteur",[1100,1325,1326,1331],{},[1118,1327,1328],{},[637,1329,1330],{},"ran10..ran14",[1118,1332,1320,1333,1335],{},[637,1334,1236],{}," pour le second projecteur",[1100,1337,1338,1343],{},[1118,1339,1340],{},[637,1341,1342],{},"ran15..ran19",[1118,1344,1320,1345,1347],{},[637,1346,1236],{}," pour le troisième projecteur",[1100,1349,1350,1355],{},[1118,1351,1352],{},[637,1353,1354],{},"ran20..ran24",[1118,1356,1320,1357,1359],{},[637,1358,1236],{}," pour le quatrième projecteur",[1100,1361,1362,1367],{},[1118,1363,1364],{},[637,1365,1366],{},"ran25..ran29",[1118,1368,1320,1369,1371],{},[637,1370,1236],{}," pour le cinquième projecteur",[18,1373,1374,1375,1377,1378,1381,1382,1384],{},"On peut remarqué que tout les canaux ",[637,1376,1236],{}," on la même valeurs, à part pour la couleur ambre du quatrième projecteur, qui, soit prends ",[637,1379,1380],{},"a + 25"," où ",[637,1383,30],{}," doit être au dessus de 100.",[83,1386,1050],{"id":1387},"poc-proof-of-concept",[18,1389,1390],{},"Avec cela on peut déjà commencé à mettre en place le type de structure de couleurs:",[624,1392,1395],{"filename":1393,"filetype":1394},"\u002Finternal\u002Fcolors\u002Frgbwa.go","golang",[14,1396,1397],{"v-slot:code":16},[631,1398,1402],{"className":1399,"code":1400,"language":1401,"meta":16,"style":16},"language-go shiki shiki-themes everforest-light","package colors\n\ntype RGBWA struct {\n    Red int\n    Green int\n    Blue int\n    White int\n    Amber int\n}\n\nfunc NewRGBWA(red int, green int, blue int, white int, amber int) *RGBWA {\n    return &RGBWA{ Red: red, Green: green, Blue: blue, White: white, Amber: amber }\n}\n","go",[637,1403,1404,1413,1418,1432,1440,1447,1454,1461,1468,1473,1477,1522,1535],{"__ignoreMap":16},[640,1405,1406,1409],{"class":642,"line":643},[640,1407,1408],{"class":707},"package",[640,1410,1412],{"class":1411},"szA_z"," colors\n",[640,1414,1415],{"class":642,"line":254},[640,1416,1417],{"emptyLinePlaceholder":266},"\n",[640,1419,1420,1424,1427,1430],{"class":642,"line":676},[640,1421,1423],{"class":1422},"sJcUA","type",[640,1425,1426],{"class":1411}," RGBWA",[640,1428,1429],{"class":1422}," struct",[640,1431,657],{"class":650},[640,1433,1434,1437],{"class":642,"line":686},[640,1435,1436],{"class":650},"    Red ",[640,1438,1439],{"class":1411},"int\n",[640,1441,1442,1445],{"class":642,"line":699},[640,1443,1444],{"class":650},"    Green ",[640,1446,1439],{"class":1411},[640,1448,1449,1452],{"class":642,"line":713},[640,1450,1451],{"class":650},"    Blue ",[640,1453,1439],{"class":1411},[640,1455,1456,1459],{"class":642,"line":726},[640,1457,1458],{"class":650},"    White ",[640,1460,1439],{"class":1411},[640,1462,1463,1466],{"class":642,"line":739},[640,1464,1465],{"class":650},"    Amber ",[640,1467,1439],{"class":1411},[640,1469,1470],{"class":642,"line":750},[640,1471,1472],{"class":650},"}\n",[640,1474,1475],{"class":642,"line":756},[640,1476,1417],{"emptyLinePlaceholder":266},[640,1478,1479,1482,1486,1489,1492,1495,1497,1500,1502,1505,1507,1510,1512,1515,1518,1520],{"class":642,"line":769},[640,1480,1481],{"class":1422},"func",[640,1483,1485],{"class":1484},"sfzdp"," NewRGBWA",[640,1487,1488],{"class":650},"(red ",[640,1490,1491],{"class":1411},"int",[640,1493,1494],{"class":650},", green ",[640,1496,1491],{"class":1411},[640,1498,1499],{"class":650},", blue ",[640,1501,1491],{"class":1411},[640,1503,1504],{"class":650},", white ",[640,1506,1491],{"class":1411},[640,1508,1509],{"class":650},", amber ",[640,1511,1491],{"class":1411},[640,1513,1514],{"class":650},") ",[640,1516,1517],{"class":646},"*",[640,1519,1236],{"class":1411},[640,1521,657],{"class":650},[640,1523,1524,1527,1530,1532],{"class":642,"line":780},[640,1525,1526],{"class":1422},"    return",[640,1528,1529],{"class":646}," &",[640,1531,1236],{"class":1411},[640,1533,1534],{"class":650},"{ Red: red, Green: green, Blue: blue, White: white, Amber: amber }\n",[640,1536,1537],{"class":642,"line":790},[640,1538,1472],{"class":650},[18,1540,1541],{},"Pour un projecteur, on peux aussi mettre ces valeurs:",[624,1543,1545],{"filename":1544,"filetype":1394},"\u002Finternal\u002Fprojector\u002Fprojector.go",[14,1546,1547],{"v-slot:code":16},[631,1548,1550],{"className":1399,"code":1549,"language":1401,"meta":16,"style":16},"package projector\n\nimport \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fcolors\"\n\ntype Projector struct {\n    Color colors.RGBWA\n}\n\nfunc NewProjector(color colors.RGBWA) *Projector {\n    return &Projector{\n        Color: color,\n    }\n}\n",[637,1551,1552,1559,1563,1572,1576,1587,1600,1604,1608,1633,1644,1649,1653],{"__ignoreMap":16},[640,1553,1554,1556],{"class":642,"line":643},[640,1555,1408],{"class":707},[640,1557,1558],{"class":1411}," projector\n",[640,1560,1561],{"class":642,"line":254},[640,1562,1417],{"emptyLinePlaceholder":266},[640,1564,1565,1569],{"class":642,"line":676},[640,1566,1568],{"class":1567},"s3SiB","import",[640,1570,1571],{"class":662}," \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fcolors\"\n",[640,1573,1574],{"class":642,"line":686},[640,1575,1417],{"emptyLinePlaceholder":266},[640,1577,1578,1580,1583,1585],{"class":642,"line":699},[640,1579,1423],{"class":1422},[640,1581,1582],{"class":1411}," Projector",[640,1584,1429],{"class":1422},[640,1586,657],{"class":650},[640,1588,1589,1592,1595,1597],{"class":642,"line":713},[640,1590,1591],{"class":650},"    Color ",[640,1593,1594],{"class":1411},"colors",[640,1596,129],{"class":650},[640,1598,1599],{"class":1411},"RGBWA\n",[640,1601,1602],{"class":642,"line":726},[640,1603,1472],{"class":650},[640,1605,1606],{"class":642,"line":739},[640,1607,1417],{"emptyLinePlaceholder":266},[640,1609,1610,1612,1615,1618,1620,1622,1624,1626,1628,1631],{"class":642,"line":750},[640,1611,1481],{"class":1422},[640,1613,1614],{"class":1484}," NewProjector",[640,1616,1617],{"class":650},"(color ",[640,1619,1594],{"class":1411},[640,1621,129],{"class":650},[640,1623,1236],{"class":1411},[640,1625,1514],{"class":650},[640,1627,1517],{"class":646},[640,1629,1630],{"class":1411},"Projector",[640,1632,657],{"class":650},[640,1634,1635,1637,1639,1641],{"class":642,"line":756},[640,1636,1526],{"class":1422},[640,1638,1529],{"class":646},[640,1640,1630],{"class":1411},[640,1642,1643],{"class":650},"{\n",[640,1645,1646],{"class":642,"line":769},[640,1647,1648],{"class":650},"        Color: color,\n",[640,1650,1651],{"class":642,"line":780},[640,1652,846],{"class":650},[640,1654,1655],{"class":642,"line":790},[640,1656,1472],{"class":650},[18,1658,1659],{},"Avec ceci mis en place, on peut maintenant mettre les valeurs ensemble puis refaire une requête:",[624,1661,1663],{"filename":1662,"filetype":1394},"main.go",[14,1664,1665],{"v-slot:code":16},[631,1666,1668],{"className":1399,"code":1667,"language":1401,"meta":16,"style":16},"package main\n\nimport (\n    \"fmt\"\n    \"net\u002Fhttp\"\n\n    \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fcolors\"\n    \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fprojector\"\n)\n\nfunc main() {\n    colorPage := \"https:\u002F\u002Fwww.duras.mobi\u002Fcouleur.php\"\n    colorMode := 1\n    colorIntensity := 255\n    color := colors.NewRGBWA(255, 125, 0, 132, 75)\n    secondColor := colors.NewRGBWA(255, 125, 0, 132, 100)\n\n    projectorGroup := []projector.Projector{\n        *projector.NewProjector(*color),\n        \u002F\u002F ... ajout des couleurs sur tout les projecteurs\n    }\n\n    res, err := http.Get(fmt.Sprintf(\n        \"%s?ran0=%d&=&ran1=%d&ran2=&ran3=&ran4=&ran5=%d&ran6=%d&ran7=%d&ran8=%d&ran9=%d&ran10=%d&ran11=%d&ran12=%d&ran13=%d&ran14=%d&ran15=%d&ran16=%d&ran17=%d&ran18=%d&ran19=%d&ran20=%d&ran21=%d&ran22=%d&ran23=%d&ran24=%d&ran25=%d&ran26=%d&ran27=%d&ran28=%d&ran29=%d\",\n        colorPage, colorMode, colorIntensity,\n        projectorGroup[0].Color.Red, projectorGroup[0].Color.Green, projectorGroup[0].Color.Blue, projectorGroup[0].Color.White, projectorGroup[0].Color.Amber,\n        \u002F\u002F ... sur toutes les valeurs\n    ))\n    if err != nil {\n        panic(err)\n    }\n    defer res.Body.Close()\n\n    if res.StatusCode != 200 {\n        panic(\"Duras Color API is not available\")\n    }\n\n    fmt.Println(res)\n}\n",[637,1669,1670,1677,1681,1688,1693,1698,1702,1707,1712,1717,1721,1731,1742,1752,1762,1802,1836,1840,1859,1877,1884,1889,1894,1917,2067,2073,2104,2110,2116,2133,2142,2147,2162,2167,2182,2194,2199,2204,2216],{"__ignoreMap":16},[640,1671,1672,1674],{"class":642,"line":643},[640,1673,1408],{"class":707},[640,1675,1676],{"class":1411}," main\n",[640,1678,1679],{"class":642,"line":254},[640,1680,1417],{"emptyLinePlaceholder":266},[640,1682,1683,1685],{"class":642,"line":676},[640,1684,1568],{"class":1567},[640,1686,1687],{"class":650}," (\n",[640,1689,1690],{"class":642,"line":686},[640,1691,1692],{"class":662},"    \"fmt\"\n",[640,1694,1695],{"class":642,"line":699},[640,1696,1697],{"class":662},"    \"net\u002Fhttp\"\n",[640,1699,1700],{"class":642,"line":713},[640,1701,1417],{"emptyLinePlaceholder":266},[640,1703,1704],{"class":642,"line":726},[640,1705,1706],{"class":662},"    \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fcolors\"\n",[640,1708,1709],{"class":642,"line":739},[640,1710,1711],{"class":662},"    \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fprojector\"\n",[640,1713,1714],{"class":642,"line":750},[640,1715,1716],{"class":650},")\n",[640,1718,1719],{"class":642,"line":756},[640,1720,1417],{"emptyLinePlaceholder":266},[640,1722,1723,1725,1728],{"class":642,"line":769},[640,1724,1481],{"class":1422},[640,1726,1727],{"class":1484}," main",[640,1729,1730],{"class":650},"() {\n",[640,1732,1733,1736,1739],{"class":642,"line":780},[640,1734,1735],{"class":650},"    colorPage ",[640,1737,1738],{"class":646},":=",[640,1740,1741],{"class":662}," \"https:\u002F\u002Fwww.duras.mobi\u002Fcouleur.php\"\n",[640,1743,1744,1747,1749],{"class":642,"line":790},[640,1745,1746],{"class":650},"    colorMode ",[640,1748,1738],{"class":646},[640,1750,1751],{"class":707}," 1\n",[640,1753,1754,1757,1759],{"class":642,"line":803},[640,1755,1756],{"class":650},"    colorIntensity ",[640,1758,1738],{"class":646},[640,1760,1761],{"class":707}," 255\n",[640,1763,1764,1767,1769,1772,1775,1778,1781,1783,1786,1788,1790,1792,1795,1797,1800],{"class":642,"line":813},[640,1765,1766],{"class":650},"    color ",[640,1768,1738],{"class":646},[640,1770,1771],{"class":650}," colors.",[640,1773,1774],{"class":1484},"NewRGBWA",[640,1776,1777],{"class":650},"(",[640,1779,1780],{"class":707},"255",[640,1782,96],{"class":650},[640,1784,1785],{"class":707},"125",[640,1787,96],{"class":650},[640,1789,1127],{"class":707},[640,1791,96],{"class":650},[640,1793,1794],{"class":707},"132",[640,1796,96],{"class":650},[640,1798,1799],{"class":707},"75",[640,1801,1716],{"class":650},[640,1803,1804,1807,1809,1811,1813,1815,1817,1819,1821,1823,1825,1827,1829,1831,1834],{"class":642,"line":824},[640,1805,1806],{"class":650},"    secondColor ",[640,1808,1738],{"class":646},[640,1810,1771],{"class":650},[640,1812,1774],{"class":1484},[640,1814,1777],{"class":650},[640,1816,1780],{"class":707},[640,1818,96],{"class":650},[640,1820,1785],{"class":707},[640,1822,96],{"class":650},[640,1824,1127],{"class":707},[640,1826,96],{"class":650},[640,1828,1794],{"class":707},[640,1830,96],{"class":650},[640,1832,1833],{"class":707},"100",[640,1835,1716],{"class":650},[640,1837,1838],{"class":642,"line":830},[640,1839,1417],{"emptyLinePlaceholder":266},[640,1841,1842,1845,1847,1850,1853,1855,1857],{"class":642,"line":843},[640,1843,1844],{"class":650},"    projectorGroup ",[640,1846,1738],{"class":646},[640,1848,1849],{"class":650}," []",[640,1851,1852],{"class":1411},"projector",[640,1854,129],{"class":650},[640,1856,1630],{"class":1411},[640,1858,1643],{"class":650},[640,1860,1861,1864,1867,1870,1872,1874],{"class":642,"line":849},[640,1862,1863],{"class":646},"        *",[640,1865,1866],{"class":650},"projector.",[640,1868,1869],{"class":1484},"NewProjector",[640,1871,1777],{"class":650},[640,1873,1517],{"class":646},[640,1875,1876],{"class":650},"color),\n",[640,1878,1880],{"class":642,"line":1879},20,[640,1881,1883],{"class":1882},"sveCK","        \u002F\u002F ... ajout des couleurs sur tout les projecteurs\n",[640,1885,1887],{"class":642,"line":1886},21,[640,1888,846],{"class":650},[640,1890,1892],{"class":642,"line":1891},22,[640,1893,1417],{"emptyLinePlaceholder":266},[640,1895,1897,1900,1902,1905,1908,1911,1914],{"class":642,"line":1896},23,[640,1898,1899],{"class":650},"    res, err ",[640,1901,1738],{"class":646},[640,1903,1904],{"class":650}," http.",[640,1906,1907],{"class":1484},"Get",[640,1909,1910],{"class":650},"(fmt.",[640,1912,1913],{"class":1484},"Sprintf",[640,1915,1916],{"class":650},"(\n",[640,1918,1920,1923,1926,1929,1932,1935,1937,1940,1942,1945,1947,1950,1952,1955,1957,1960,1962,1965,1967,1970,1972,1975,1977,1980,1982,1985,1987,1990,1992,1995,1997,2000,2002,2005,2007,2010,2012,2015,2017,2020,2022,2025,2027,2030,2032,2035,2037,2040,2042,2045,2047,2050,2052,2055,2057,2060,2062,2065],{"class":642,"line":1919},24,[640,1921,1922],{"class":662},"        \"",[640,1924,1925],{"class":1484},"%s",[640,1927,1928],{"class":662},"?ran0=",[640,1930,1931],{"class":1484},"%d",[640,1933,1934],{"class":662},"&=&ran1=",[640,1936,1931],{"class":1484},[640,1938,1939],{"class":662},"&ran2=&ran3=&ran4=&ran5=",[640,1941,1931],{"class":1484},[640,1943,1944],{"class":662},"&ran6=",[640,1946,1931],{"class":1484},[640,1948,1949],{"class":662},"&ran7=",[640,1951,1931],{"class":1484},[640,1953,1954],{"class":662},"&ran8=",[640,1956,1931],{"class":1484},[640,1958,1959],{"class":662},"&ran9=",[640,1961,1931],{"class":1484},[640,1963,1964],{"class":662},"&ran10=",[640,1966,1931],{"class":1484},[640,1968,1969],{"class":662},"&ran11=",[640,1971,1931],{"class":1484},[640,1973,1974],{"class":662},"&ran12=",[640,1976,1931],{"class":1484},[640,1978,1979],{"class":662},"&ran13=",[640,1981,1931],{"class":1484},[640,1983,1984],{"class":662},"&ran14=",[640,1986,1931],{"class":1484},[640,1988,1989],{"class":662},"&ran15=",[640,1991,1931],{"class":1484},[640,1993,1994],{"class":662},"&ran16=",[640,1996,1931],{"class":1484},[640,1998,1999],{"class":662},"&ran17=",[640,2001,1931],{"class":1484},[640,2003,2004],{"class":662},"&ran18=",[640,2006,1931],{"class":1484},[640,2008,2009],{"class":662},"&ran19=",[640,2011,1931],{"class":1484},[640,2013,2014],{"class":662},"&ran20=",[640,2016,1931],{"class":1484},[640,2018,2019],{"class":662},"&ran21=",[640,2021,1931],{"class":1484},[640,2023,2024],{"class":662},"&ran22=",[640,2026,1931],{"class":1484},[640,2028,2029],{"class":662},"&ran23=",[640,2031,1931],{"class":1484},[640,2033,2034],{"class":662},"&ran24=",[640,2036,1931],{"class":1484},[640,2038,2039],{"class":662},"&ran25=",[640,2041,1931],{"class":1484},[640,2043,2044],{"class":662},"&ran26=",[640,2046,1931],{"class":1484},[640,2048,2049],{"class":662},"&ran27=",[640,2051,1931],{"class":1484},[640,2053,2054],{"class":662},"&ran28=",[640,2056,1931],{"class":1484},[640,2058,2059],{"class":662},"&ran29=",[640,2061,1931],{"class":1484},[640,2063,2064],{"class":662},"\"",[640,2066,673],{"class":650},[640,2068,2070],{"class":642,"line":2069},25,[640,2071,2072],{"class":650},"        colorPage, colorMode, colorIntensity,\n",[640,2074,2076,2079,2081,2084,2086,2089,2091,2094,2096,2099,2101],{"class":642,"line":2075},26,[640,2077,2078],{"class":650},"        projectorGroup[",[640,2080,1127],{"class":707},[640,2082,2083],{"class":650},"].Color.Red, projectorGroup[",[640,2085,1127],{"class":707},[640,2087,2088],{"class":650},"].Color.Green, projectorGroup[",[640,2090,1127],{"class":707},[640,2092,2093],{"class":650},"].Color.Blue, projectorGroup[",[640,2095,1127],{"class":707},[640,2097,2098],{"class":650},"].Color.White, projectorGroup[",[640,2100,1127],{"class":707},[640,2102,2103],{"class":650},"].Color.Amber,\n",[640,2105,2107],{"class":642,"line":2106},27,[640,2108,2109],{"class":1882},"        \u002F\u002F ... sur toutes les valeurs\n",[640,2111,2113],{"class":642,"line":2112},28,[640,2114,2115],{"class":650},"    ))\n",[640,2117,2119,2122,2125,2128,2131],{"class":642,"line":2118},29,[640,2120,2121],{"class":1422},"    if",[640,2123,2124],{"class":650}," err ",[640,2126,2127],{"class":646},"!=",[640,2129,2130],{"class":707}," nil",[640,2132,657],{"class":650},[640,2134,2136,2139],{"class":642,"line":2135},30,[640,2137,2138],{"class":1484},"        panic",[640,2140,2141],{"class":650},"(err)\n",[640,2143,2145],{"class":642,"line":2144},31,[640,2146,846],{"class":650},[640,2148,2150,2153,2156,2159],{"class":642,"line":2149},32,[640,2151,2152],{"class":1422},"    defer",[640,2154,2155],{"class":650}," res.Body.",[640,2157,2158],{"class":1484},"Close",[640,2160,2161],{"class":650},"()\n",[640,2163,2165],{"class":642,"line":2164},33,[640,2166,1417],{"emptyLinePlaceholder":266},[640,2168,2170,2172,2175,2177,2180],{"class":642,"line":2169},34,[640,2171,2121],{"class":1422},[640,2173,2174],{"class":650}," res.StatusCode ",[640,2176,2127],{"class":646},[640,2178,2179],{"class":707}," 200",[640,2181,657],{"class":650},[640,2183,2185,2187,2189,2192],{"class":642,"line":2184},35,[640,2186,2138],{"class":1484},[640,2188,1777],{"class":650},[640,2190,2191],{"class":662},"\"Duras Color API is not available\"",[640,2193,1716],{"class":650},[640,2195,2197],{"class":642,"line":2196},36,[640,2198,846],{"class":650},[640,2200,2202],{"class":642,"line":2201},37,[640,2203,1417],{"emptyLinePlaceholder":266},[640,2205,2207,2210,2213],{"class":642,"line":2206},38,[640,2208,2209],{"class":650},"    fmt.",[640,2211,2212],{"class":1484},"Println",[640,2214,2215],{"class":650},"(res)\n",[640,2217,2219],{"class":642,"line":2218},39,[640,2220,1472],{"class":650},[18,2222,2223],{},"La requête passe, Le chateau de Duras change de couleur !",[624,2225,2226],{"filename":1070,"filetype":1071},[14,2227,2228],{"v-slot:code":16},[631,2229,2232],{"className":2230,"code":2231,"language":1079},[1077],"200 OK\n200 HTTP\u002F2.0 2 0 map[Content-Length:[0]\nContent-Type:[text\u002Fhtml; charset=us-ascii]\nDate:[Wed, 24 Dec 2025 13:33:07 GMT]\nServer:[nginx]] {} 0 [] false false map[] 0xc0000ee000 0xc000183740\n",[637,2233,2231],{"__ignoreMap":16},[83,2235,1056],{"id":2236},"création-du-cli",[18,2238,2239,2240,129],{},"Maintenant que l'on a réussi à recevoir une réponse positive avec le PoC (Proof of Concept), nous pouvons nous lancer sur la création du cli. Je refactorise le code pour mettre la création de requetes dans le fichier ",[637,2241,2242],{},"\u002Finternal\u002Fapi\u002Fsend.go",[18,2244,2245,2246,2253],{},"Pour le cli on va utilisé ",[30,2247,2250],{"href":2248,"rel":2249},"https:\u002F\u002Fgithub.com\u002Fcharmbracelet\u002Fbubbletea",[93],[637,2251,2252],{},"bubbletea"," un tui maker pour golang.",[18,2255,2256,2257,2260],{},"J'ai ajouter la possibilité d'avoir des ",[637,2258,2259],{},"presets"," pour pouvoir ajouter des couleurs prédéfini, mais aussi une possibilité de customibilisé les couleurs qui sont envoyé:",[624,2262,2264],{"filename":2263,"filetype":1394},"\u002Finternal\u002Fpresets\u002Fdata.go",[14,2265,2266],{"v-slot:code":16},[631,2267,2269],{"className":1399,"code":2268,"language":1401,"meta":16,"style":16},"package preset\n\nimport \"github.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli\u002Finternal\u002Fcolors\"\n\nvar Presets = []Preset{\n    {\n        Name: \"France\",\n        Colors: []*colors.RGBWA{\n            colors.NewRGBWA(0, 0, 255, 125, 75),\n            \u002F\u002F ... fois 5\n        },\n    },\n    \u002F\u002F ...\n    {\n        Name: \"Custom\",\n        Colors: []*colors.RGBWA{\n            colors.NewRGBWA(0, 0, 0, 0, 0),\n            \u002F\u002F ... fois 5\n        },\n    },\n}\n",[637,2270,2271,2278,2282,2288,2292,2309,2314,2324,2339,2369,2374,2378,2382,2387,2391,2400,2414,2442,2446,2450,2454],{"__ignoreMap":16},[640,2272,2273,2275],{"class":642,"line":643},[640,2274,1408],{"class":707},[640,2276,2277],{"class":1411}," preset\n",[640,2279,2280],{"class":642,"line":254},[640,2281,1417],{"emptyLinePlaceholder":266},[640,2283,2284,2286],{"class":642,"line":676},[640,2285,1568],{"class":1567},[640,2287,1571],{"class":662},[640,2289,2290],{"class":642,"line":686},[640,2291,1417],{"emptyLinePlaceholder":266},[640,2293,2294,2297,2300,2302,2304,2307],{"class":642,"line":699},[640,2295,2296],{"class":646},"var",[640,2298,2299],{"class":650}," Presets ",[640,2301,654],{"class":646},[640,2303,1849],{"class":650},[640,2305,2306],{"class":1411},"Preset",[640,2308,1643],{"class":650},[640,2310,2311],{"class":642,"line":713},[640,2312,2313],{"class":650},"    {\n",[640,2315,2316,2319,2322],{"class":642,"line":726},[640,2317,2318],{"class":650},"        Name: ",[640,2320,2321],{"class":662},"\"France\"",[640,2323,673],{"class":650},[640,2325,2326,2329,2331,2333,2335,2337],{"class":642,"line":739},[640,2327,2328],{"class":650},"        Colors: []",[640,2330,1517],{"class":646},[640,2332,1594],{"class":1411},[640,2334,129],{"class":650},[640,2336,1236],{"class":1411},[640,2338,1643],{"class":650},[640,2340,2341,2344,2346,2348,2350,2352,2354,2356,2358,2360,2362,2364,2366],{"class":642,"line":750},[640,2342,2343],{"class":650},"            colors.",[640,2345,1774],{"class":1484},[640,2347,1777],{"class":650},[640,2349,1127],{"class":707},[640,2351,96],{"class":650},[640,2353,1127],{"class":707},[640,2355,96],{"class":650},[640,2357,1780],{"class":707},[640,2359,96],{"class":650},[640,2361,1785],{"class":707},[640,2363,96],{"class":650},[640,2365,1799],{"class":707},[640,2367,2368],{"class":650},"),\n",[640,2370,2371],{"class":642,"line":756},[640,2372,2373],{"class":1882},"            \u002F\u002F ... fois 5\n",[640,2375,2376],{"class":642,"line":769},[640,2377,827],{"class":650},[640,2379,2380],{"class":642,"line":780},[640,2381,753],{"class":650},[640,2383,2384],{"class":642,"line":790},[640,2385,2386],{"class":1882},"    \u002F\u002F ...\n",[640,2388,2389],{"class":642,"line":803},[640,2390,2313],{"class":650},[640,2392,2393,2395,2398],{"class":642,"line":813},[640,2394,2318],{"class":650},[640,2396,2397],{"class":662},"\"Custom\"",[640,2399,673],{"class":650},[640,2401,2402,2404,2406,2408,2410,2412],{"class":642,"line":824},[640,2403,2328],{"class":650},[640,2405,1517],{"class":646},[640,2407,1594],{"class":1411},[640,2409,129],{"class":650},[640,2411,1236],{"class":1411},[640,2413,1643],{"class":650},[640,2415,2416,2418,2420,2422,2424,2426,2428,2430,2432,2434,2436,2438,2440],{"class":642,"line":830},[640,2417,2343],{"class":650},[640,2419,1774],{"class":1484},[640,2421,1777],{"class":650},[640,2423,1127],{"class":707},[640,2425,96],{"class":650},[640,2427,1127],{"class":707},[640,2429,96],{"class":650},[640,2431,1127],{"class":707},[640,2433,96],{"class":650},[640,2435,1127],{"class":707},[640,2437,96],{"class":650},[640,2439,1127],{"class":707},[640,2441,2368],{"class":650},[640,2443,2444],{"class":642,"line":843},[640,2445,2373],{"class":1882},[640,2447,2448],{"class":642,"line":849},[640,2449,827],{"class":650},[640,2451,2452],{"class":642,"line":1879},[640,2453,753],{"class":650},[640,2455,2456],{"class":642,"line":1886},[640,2457,1472],{"class":650},[18,2459,2460,2461,2464,2465,2468,2469,2474,2475,2478,2479,2481],{},"Les couleurs seront dans une liste dans laquelle on peux choisir au lancement du cli. pour choisir entre la view où l'on peut mettre ses propre valeurs et celle où il y a les presets, le fichier ",[637,2462,2463],{},"view.go"," gère le fonctionnement, pour plus d'information sur le ",[637,2466,2467],{},"Model",", vous pouvez voir le projet sur ",[30,2470,2473],{"href":2471,"rel":2472},"https:\u002F\u002Fgithub.com\u002FLelouchFR\u002Fduras-castle-color-changer-cli",[93],"GitHub",". Pour passer sur la view custom pour mettre ses valeurs, on peut choisir le preset ",[637,2476,2477],{},"Custom"," qui est un preset avec les valeurs de couleurs qui sont tous à ",[637,2480,1127],{},". Les valeurs seront changer au moment où l'on les rentre dans la vue.",[83,2483,2485],{"id":2484},"résultat-final","Résultat final",[71,2487,290,2489,2504],{"className":2488},[74,75,76,77,78,79],[18,2490,2493,2494,2496,2498,2499,2501,2503],{"className":2491},[294,2492],"px-4","En partant d'une simple observation sur le site officiel, un peu de rétro-ingénierie et de curiosité, j'ai réussi à comprendre la structure de l'API et la modélisation de ses données pour en faire un CLI.",[62,2495],{},[62,2497],{},"\n        Ce projet illustre surtout combien des systèmes qui semblent fermés peuvent être explorés et compris grâve à des outils et une bonne méthodologie. L'objectif n'était pas uniquement de modifier des lumières, mais aussi de bâtir quelque chose de soigné, réutilisable et agréable à utiliser.",[62,2500],{},[62,2502],{},"\n        Bien sûr, ce type d'expérimentation doir rester dans un cadre respectueux et strictement technique. Mais c'est également ce qui rend ce genre de projet captivant, transformer une idée farfelue en un outil concret qui fonctionne réellement. Et soyons honnêtes, contrôler la couleur d'un château depuis un terminal a tout de même une certaine classe.",[317,2505],{":controls":319,"poster":2506,"src":2507},"\u002Fassets\u002Fimages\u002Fblogposts\u002F24-12-25.png","\u002Fassets\u002Fvideos\u002Fblogposts\u002Fcontent\u002Fduras-cli.mp4",[71,2509,2513],{"className":2510},[2511,2512],"w-2\u002F3","mx-auto",[2514,2515],"image-galery",{":images":2516},"[\"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fdccc_presentation.png\", \"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fdccc_1.png\", \"\u002Fassets\u002Fimages\u002Fblogposts\u002Fcontent\u002Fdccc_2.png\"]",[1000,2518,2519],{},"html pre.shiki code .sFsDM, html code.shiki .sFsDM{--shiki-default:#DF69BA}html pre.shiki code .szA_z, html code.shiki .szA_z{--shiki-default:#3A94C5}html pre.shiki code .sJcUA, html code.shiki .sJcUA{--shiki-default:#F85552}html pre.shiki code .sNieu, html code.shiki .sNieu{--shiki-default:#5C6A72}html pre.shiki code .sfzdp, html code.shiki .sfzdp{--shiki-default:#8DA101}html pre.shiki code .sWOlJ, html code.shiki .sWOlJ{--shiki-default:#F57D26}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .s3SiB, html code.shiki .s3SiB{--shiki-default:#35A77C}html pre.shiki code .soamM, html code.shiki .soamM{--shiki-default:#DFA000}html pre.shiki code .sveCK, html code.shiki .sveCK{--shiki-default:#939F91;--shiki-default-font-style:italic}",{"title":16,"searchDepth":254,"depth":254,"links":2521},[2522,2525,2526,2527],{"id":1061,"depth":254,"text":1044,"children":2523},[2524],{"id":1219,"depth":676,"text":1220},{"id":1387,"depth":254,"text":1050},{"id":2236,"depth":254,"text":1056},{"id":2484,"depth":254,"text":2485},"Comment j'ai rétro-ingénierer l'api de couleur du château de Duras pour en faire une interface de ligne de commande ?","24\u002F12\u002F2025 11:50",{"sitemap":2531},{"lastmod":2532},"2025-12-24",{"title":273,"description":16},"rK9DgxJNxrMKjC0R_PVkiO008Ituy7p49ZBVHSFUYuA",{"id":4,"title":5,"author":6,"body":2536,"caption":259,"cover_image":260,"date":261,"description":16,"extension":262,"meta":2695,"navigation":266,"path":267,"seo":2697,"stem":269,"__hash__":270},{"type":8,"value":2537,"toc":2690},[2538,2568,2570,2572,2576,2616,2618,2625,2627,2648,2650,2652,2654,2656,2684,2686,2688],[11,2539,2540,2544],{},[14,2541,2542],{"v-slot:title":16},[18,2543,20],{},[14,2545,2546],{"v-slot:details":16},[24,2547,2548,2552,2556,2560,2564],{},[27,2549,2550],{},[30,2551,33],{"href":32},[27,2553,2554],{},[30,2555,39],{"href":38},[27,2557,2558],{},[30,2559,45],{"href":44},[27,2561,2562],{},[30,2563,51],{"href":50},[27,2565,2566],{},[30,2567,57],{"href":56},[59,2569],{},[62,2571],{},[65,2573,2574],{},[18,2575,69],{},[71,2577,2579,2610],{"className":2578},[74,75,76,77,78,79],[71,2580,2581,2583,2606,2608],{},[83,2582,33],{"id":85},[18,2584,88,2585,96,2588,102,2591,108,2594,96,2597,96,2600,102,2603,129],{},[30,2586,95],{"href":91,"rel":2587,"target":94},[93],[30,2589,101],{"href":99,"rel":2590,"target":94},[93],[30,2592,107],{"href":105,"rel":2593,"target":94},[93],[30,2595,113],{"href":111,"rel":2596,"target":94},[93],[30,2598,118],{"href":116,"rel":2599,"target":94},[93],[30,2601,123],{"href":121,"rel":2602,"target":94},[93],[30,2604,128],{"href":126,"rel":2605,"target":94},[93],[83,2607,39],{"id":132},[18,2609,135],{},[71,2611,2612],{},[18,2613,2614,145],{},[141,2615],{"alt":143,"src":144},[83,2617,45],{"id":148},[18,2619,151,2620,157,2623,162],{},[30,2621,156],{"href":154,"rel":2622},[93],[30,2624,161],{"href":160},[62,2626],{},[71,2628,2630,2639],{"className":2629},[74,75,76,77,78,79],[71,2631,2633,2635,2637],{"className":2632},[171,172,78],[18,2634,175],{},[18,2636,178],{},[18,2638,181],{},[71,2640,2642,2644],{"className":2641},[171,172,78,185],[187,2643],{"after-image":189,"before-image":190,"id":191},[65,2645,2646],{},[18,2647,196],{},[62,2649],{},[18,2651,201],{},[18,2653,204],{},[83,2655,51],{"id":207},[71,2657,2659,2670],{"className":2658},[74,75,76,77,78,211],[71,2660,2662,2664,2666,2668],{"className":2661},[171,172,78],[18,2663,217],{},[18,2665,220],{},[18,2667,223],{},[18,2669,226],{},[71,2671,2673,2677],{"className":2672},[171,172,78],[18,2674,2675],{},[141,2676],{"alt":234,"src":235},[65,2678,2679],{},[18,2680,2681,243],{},[30,2682,101],{"href":99,"rel":2683,"target":94},[93],[83,2685,57],{"id":246},[18,2687,249],{},[18,2689,252],{},{"title":16,"searchDepth":254,"depth":254,"links":2691},[2692,2693,2694],{"id":148,"depth":254,"text":45},{"id":207,"depth":254,"text":51},{"id":246,"depth":254,"text":57},{"sitemap":2696},{"lastmod":265},{"title":5,"description":16},1792926046787]