1 UNIVERSITATEA DIN BUCUREȘTI FACULTATEA DE MATEMATICA ȘI INFORMATICĂ SPECIALIZAREA INFORMATICĂ Lucrare de licență APLICAȚIE WEB DE EDITARE A… [603887]
1 UNIVERSITATEA DIN BUCUREȘTI FACULTATEA DE MATEMATICA ȘI INFORMATICĂ SPECIALIZAREA INFORMATICĂ Lucrare de licență APLICAȚIE WEB DE EDITARE A SITE-URILOR Coordonator științific: Absolvent: [anonimizat]ó Alexandru-Andrei București, iulie 2020
2 Generalități Am ales să îmi numesc aplicația construită pentru lucrarea de licență Visual Web-Editor. Aceasta își propune să ajute atât oamenii cu cunoștințe tehnice cât și pe cei care nu posedă astfel de abilități în editarea paginilor web. Tema aplicației constă în editarea unui web-site indiferent de tehnologiile folosite la crearea acestuia. Aplicația funcționează atât pentru site-uri servite static de către server cât și pentru pagini web de tip SPA. Singurele configurații necesare pentru un utilizator sunt crearea unui cont și introducerea în codul sursă al paginii a unui fișier de tip JavaScript care ulterior să permită comunicarea cu editorul.
3 Cuprins Introducere: ………………………………………………………………………………………………………………. 5 Motivarea alegerii: ………………………………………………………………………………………………… 5 Obiectivele aplicației: …………………………………………………………………………………………….. 5 Structura lucrării: …………………………………………………………………………………………………. 5 1. Tehnologii folosite………………………………………………………………………………………………. 6 I. Limbaje de programare …………………………………………………………………………………. 6 II. Front-End ……………………………………………………………………………………………………… 7 III. Back-End ………………………………………………………………………………………………………. 9 IV. Infrastructura …………………………………………………………………………………………….. 9 2. Arhitectura aplicației ………………………………………………………………………………………… 10 3. Mediul de dezvoltare …………………………………………………………………………………………. 11 I. Conceptul de „monorepo” …………………………………………………………………………….. 11 II. Micro-Serviciile AWS folosite ……………………………………………………………………….. 11 III. Urcarea serverului în cloud …………………………………………………………………………… 11 IV. Urcarea aplicației font-end în cloud …………………………………………………………… 13 4. Descrierea Aplicației …………………………………………………………………………………………. 14 I. Crearea unui cont ………………………………………………………………………………………… 14 a. Front End ………………………………………………………………………………………………….. 14 b. Back End …………………………………………………………………………………………………… 14 c. Componente folosite la crearea unui cont ………………………………………………………. 15 II. Autentificarea ………………………………………………………………………………………………. 15 a. Front …………………………………………………………………………………………………………. 15 b. Back …………………………………………………………………………………………………………. 16 c. Componente folosite pentru …………………………………………………………………………. 17
4 III. Pagina principală …………………………………………………………………………………………. 17 a. Front …………………………………………………………………………………………………………. 17 b. Back …………………………………………………………………………………………………………. 19 IV. Procesul de editare ……………………………………………………………………………………. 20 a. Front …………………………………………………………………………………………………………. 20 b. Back …………………………………………………………………………………………………………. 26 V. Comunicarea cu pagina ………………………………………………………………………………… 28 a. Implementarea ……………………………………………………………………………………………. 28 b. Gestionarea evenimentului „mouse over” ……………………………………………………… 28 c. Gestionarea evenimentului „click” pentru selectarea unui ……………………………….. 29 d. Găsirea căii către element ……………………………………………………………………………. 29 e. Găsirea unui element folosind calea ……………………………………………………………… 30 f. Gestionarea mesajelor primite de la ………………………………………………………………. 31 g. Gestionarea modificărilor: …………………………………………………………………………… 33 h. Gestionarea design-urilor active …………………………………………………………………… 34 VI. Introducere a „react hooks” ……………………………………………………………………… 34 VII. Gestionarea rutelor …………………………………………………………………………………… 35 VIII. Algoritmul de criptare Blowfish și functia Bcrypt ………………………………………. 36 a. Algoritmul Blowfish …………………………………………………………………………………… 36 b. Funcția Bcrypt ……………………………………………………………………………………………. 38 Concluzii …………………………………………………………………………………………………………………. 39
5 Introducere: Motivarea alegerii: Am ales această temă de licența deoarece am dorit să explorez modul în care două pagini web diferite pot comunica una cu cealaltă prin intermediul unui element de tip iframe. De asemenea un alt motiv important a fost reprezentat de dorința de a dezvolta o aplicație întreagă de la început până la final folosind tehnologii moderne, de actualitate, acest lucru reprezentând o oportunitate de extindere a cunoștințelor. Obiectivele aplicației: Aplicația își propune reușirea creării unei legături intre două pagini web printr-un element de tip iframe și apoi reușirea editării paginii web încărcată în acest element . Structura lucrării: Lucrarea conține 4 capitole: • Primul capitol vorbește despre tehnologiile folosite la modul general. • Al doilea capitol conține informații despre arhitectura și drumul pe care utilizatorul îl urmează, în mare, pentru a folosi aplicația. • Al treilea capitol conține descrie mediul de lucru ales și informatii despre serviciile cloud folosite. • Ultimul capitol descrie implementarea aplicației de front-end, serverului de back-end, a fișierului JS de comunicare cât și unele specificații ale tehnologiilor care m-au ajutat.
6 1. Tehnologii folosite I. Limbaje de programare Primul limbaj de programare pe care am ales să îl folosesc este JavaScript. JavaScript este un limbaj de programare flexibil, care oferă o varietate mare de funcționalități. Aceste funcționalități le includ atât pe cele baza pentru procesare de date, lucru cu fișiere ( HTML, TXT, etc… ) cât și pe cele care îți permit manipularea DOM-ului virtual al unei pagini web, procesare asincronă de date, conectivitate cu baza de date etc… JavaScript este un limbaj interpretat cu paradigmă multiplă, oferind astfel opțiunea de a lucra în mod procedural, orientat pe obiecte sau funcțional. Limbajul a cunoscut în ultimii ani o ascensiune rapidă în preferințele publicului trecând de la un limbaj folosit strict pentru front-end la un limbaj folosit atât pentru front-end cât și pentru back-end, procesare de date și chiar și învățare automata prin efortul celor de la Google ( Tensorflow JS ). În spatele acestei ascensiuni se afla mediul de dezvoltare numit Node creat de Ryan Dahl în 2009. Pe lângă tehnologiile apărute pentru back-end și analiza de date aplicațiile de front-end au suferit și ele mari schimbări în ultimii ani. Companii mari precum Google sau Facebook au creat framework-uri precum React și Angular care să faciliteze și să optimizeze la maxim infrastructura unei pagini web. JavaScript a ajuns în doar un deceniu un limbaj folosit de toate dispozitivele noastre de la computere, tablete și telefoane până la plăcuțe Arduino și NodeBots. Decizia de a folosi acest limbaj a constat în ușurința cu care se pot găsi resurse și cursuri pe internet,prin comunitatea dedicată acestui limbaj, cât și ușurința de a-l învăța pentru oricine are experiență în familia limbajelor derivate din C. [XXVII] Pentru a extinde eficiența acestui limbaj am ales să adaug proiectului limbajul TypeScript, un limbaj open-source creat și menținut de Microsoft. TypeScript este de fapt un super set al limbajului JavaScript care adaugă funcționalitatea de declarare statica a variabilelor. Din moment ce TypeScript se compilează în cele din urma în JavaScript orice program scris anterior în JS rămâne valid și poate fi purtat în limbajul TypeScript. [XXVIII]
7 Topul celor mai populare limbaje de programare.
Figura 1 [V] II. Front-End a. React React este un framework de JavaScript compatibil și cu TypeScript utilizat în crearea interfețelor pentru utilizatori. Acesta a fost creat și apoi menținut de Facebook. React oferă posibilitatea de a crea pagini web rapide, interactive și scalabile. React împarte o pagina web în componente care își mențin propria stare, acestea putând fi refolosite în diferite locuri din aplicație. Acest framework permite folosirea componentelor în orice pagina web indiferent de tehnologiile folosite anterior. Eu ca programator am opțiunea de a crea propriile componente din elemente care mimează sintaxa HTML și de a le refolosi în aplicație fără nevoia de a duplica codul. Aceste componente se folosesc de o extensie a JS numită JSX, pentru TypeScript acesta se numește TSX. Prin intermediul React putem crea aplicații de tip SPA ( Single Page Application ) aceste aplicații sunt mult mai rapide decât site-urile web convenționale care pentru fiecare pagină diferită trebuie să trimită un request la server pentru a semnala schimbarea unei rute și pentru a primi înapoi codul paginii ce trebuie afișată utilizatorului. Într-o aplicație de tip single page tot codul de tip HTML, JS și CSS este încărcat o singură dată de către browser, iar diferitele componente sunt afișate dinamic
8 pe ecran în funcție de schimbările stării aplicației. Astfel pagina nu se reîncarcă niciodată. Am ales această tehnologie deoarece o consider cea mai flexibila dintre toate tehnologiile pentru browser UI ( User interface ) moderne, aceasta flexibilitate mi-a permis să structurez aplicația așa cum am văzut eu adecvat. De asemenea un alt factor important a fost comunitatea dedicată și resursele abundente pentru învățarea acestui framework.
Figura 2 [I, IV, XIII] b. React-Bootstrap Bootstrap este o bibliotecă open source de componente React ce servesc ca un punct de plecare pentru anumite elemente ale interfeței. Aceste componente putând fi modificate pentru a îndeplini diferite scopuri în pagină. [III] c. SASS SASS () este un limbaj de stilizare a elementelor HTML care se compilează în CSS acesta permite folosirea variabilelor, nesting-ului de reguli și a funcțiilor. SASS ajută la menținerea organizată a fișierelor mari de stilizare. [VI]
9 III. Back-End a. NestJS NestJS este un framework modern folosit pentru crearea de aplicații eficiente și scalabile de tip server. NestJS este construit deasupra mediului de dezvoltare NodeJS, are suport pentru TypeScript și combină elemente de programare orientată pe obiecte și programare funcțională. Acest framework se folosește de alte framework-uri de tip HTTP server precum Express. Nest permite un nivel de abstractizare mai ridicat fata de Express dar de asemenea expune API-ul direct programatorului. [II, VIII] b. MongoDB MongoDB este o bază de date orientată pe documente, clasificată ca NoSQL. Aceasta folosește documente de tip JSON ( JavaScript object ) alături de scheme ale acestora. MongoDB este o bază de date distribuită la bază rezultând astfel un puternic factor de scalabilitate indiferent de geografie și de amplasarea clusterului. [XXVIII, XVII] IV. Infrastructura a. MongoDB Atlas MongoDB Atlas este un serviciu global pentru crearea bazelor de date de tip MongoDB, acesta este ținut în cloud.[XVII] b. AWS ( Amazon web services ) AWS este un serviciu Amazon care furnizează infrastructura. Aceasta infrastructură variază de la hostare pagini web până la clustere pentru procesare distribuită. [X, XXVIII]
10 2. Arhitectura aplicației
Figura 3 Diagrama anterioară arată modul în care un utilizator interacționează cu aplicația. Din aceasta figură se observa modul de utilizare. – Scopul principal al aplicației este editarea unei pagini web deja existente. – Utilizatorul creează un cont la prima accesare prin introducerea unei adrese de e-mail și a unei parole. – Utilizatorul descarcă fișierul JS necesar pentru comunicarea între editor și aplicație, iar apoi îl introduce în pagina web proprie. – Utilizatorul introduce URL-ul aplicației, acesta apoi se încarcă într-un element de tip iframe. – Utilizatorul face modificări iar apoi salvează acest set de modificări ca un „design” și îl activează. – Utilizatorul vede în pagina proprie schimbările făcute în editor.
11 3. Mediul de dezvoltare I. Conceptul de „monorepo” Un „monorepo” este o strategie de dezvoltate a programelor informatice care propune păstrarea codului mai multor proiecte în același repository. În cazul aplicației create de mine serverul NestJS și aplicația React de front-end împart același repository. Motivul pentru care am ales să îmi structurez proiectul sub forma unui monorepo a constat în nevoia de a avea dependențele comune o sigură dată pentru a optimiza spațiul și tehnologiile folosite. De asemenea în cadrul unui „commit” în git pot vedea în acest mod toate flow-urile create de la un capăt la celălalt al aplicației. Pentru a crea un monorepo și a-mi gestiona proiectul m-am folosit de mediul de dezvoltare „NX” creat de către NRWL. Acest mediu de dezvoltare îmi oferă unelte pentru crearea de noi componente rapid, construirea unei versiuni gata de producție și pentru dezvoltarea rapida a aplicației. Un exemplu ar fi reprezentat de funcționalitatea de „live-reload” care îmi recompilează codul atunci când salvez o nouă linie, acest lucru ajutându-mi mult productivitatea.[XXVIII, VII, XII, XVI] II. Micro-Serviciile AWS folosite Pentru a urca aplicația în cloud am folosit doua micro servicii de la AWS. a. Amazon Elastic Compute Cloud ( EC2 ) EC2 este un micro serviciu de la Amazon care oferă opțiunea de a închiria o mașină virtuală (numită „instanță”). Un utilizator al acestui serviciu poate configura o instanță așa cum își dorește.[X, XXVIII] b. Amazon Amplify Platforma Amplify este folosită pentru crearea aplicațiilor de tip WEB sau mobile. Aceasta pune la dispoziție un mod simplu de a urca în cloud aplicații precum cele construite în React. Accesul la aceste micro servicii a fost furnizat prin programul „Educate” derulat de cei de la Amazon.[X] III. Urcarea serverului în cloud
12 Pentru urcarea serverului de NestJS în cloud mai întâi a trebuit să îmi urc codul pe platforma GitHub. După urcarea codului am accesat platforma AWS și am pornit o instanță din micro serviciul EC2, instanța fiind de tip T2. După pornirea aceste instanțe, m-am conectat la ea din terminalul computerului prin intermediul protocolului SSH (Secure Shell). După conectare am folosit package managerul „yum” pentru a descarcă git. Odată descărcat am continuat prin a îmi clona repository-ul pe mașină. a. Cu repository-ul clonat am început pregătirea pentru a lansa serverul. Am rulat următoarele comenzi în ordine: • sudo yum install Node ( pentru a instala ultima versiune a Node pe mașină) • sudo yum install yarn (pentru a instala yarn, package managerul proiectului, pe mașină) • yarn install (pentru a îmi instala toate dependențele necesare proiectului din moment ce aceste nu au fost urcate în GitHub) • yarn run build –prod (pentru a construi versiunea gata de deploy a codului, aceasta comanda se folosește de uneltele puse la dispoziție de mediul de dezvoltare NX pentru a înlocuii variabilele specifice modului de dezvoltare cu variabile gata pentru producție) Odată terminată operația de construire, codul serverului a fost transformat în JavaScript pur și se află sub folderul „dist/apps” Figura 4 • acum cu codul serverului compilat am avut nevoie de tool-ul pentru terminal numit „Node forever” pentru rularea serverului în mod continuu. • Pentru a porni serverul am folosit comanda „forever start main.js” Figura 5
13 [XXII, XXIV, XXV] IV. Urcarea aplicației font-end în cloud Platforma Amplify oferă un mod mai ușor de a urca aplicații de tip front-end în cloud. Aceasta necesită doar calea către repository-ul de github și editarea unui simplu fișier de tip YML.
Figura 6 După cum se poate observa în figura anterioara tot ce a trebuit să îi specific sunt comenzile de instalare, de construire a versiunii pentru producție și calea unde să găsească fișierele compilate.
Figura 7
14 4. Descrierea Aplicației I. Crearea unui cont a. Front End La accesarea aplicației prima dată utilizatorul va fi adus pe pagina de autentificare acesta va trebui să acceseze link-ul pentru crearea unui cont. În acest moment modalul de autentificare va fi înlocuit de către React, fără ca pagina să fie reîncărcată, cu modalul pentru crearea unui cont nou.
Figura 8 După introducerea datelor utilizator va apăsa butonul “Sign up”. În momentul apăsării butonului front-end-ul va trimite un request HTTP de tip POST către serverul de NestJS și va aștepta un răspuns care să ii spună că utilizatorul a fost creat cu succes. În momentul în care acest răspuns va fi primit, aplicația va redirecționa utilizatorul către pagina de autentificare încă o data prin înlocuirea componentei „SignUpModal” cu componenta „LoginModal”. b. Back End Odată ce utilizatorul a introdus datele și a apăsat butonul „Sign Up” aplicația de front-end va trimite către server aceste informații. Serverul de back-end va primi datele la ruta „api/auth”, acesta va verifica că email-ul nu a mai fost folosit până acum pentru crearea unui cont. în cazul în care această adresa e-mail este deja folosită serverul va trimite înapoi către aplicația React un răspuns care îl va informa pe utilizator și îl va indemna să folosească altă
15 adresa. În cazul în care adresa de e-mail nu este folosită deja aplicația de NestJS trece la procesarea datelor în acest moment parola utilizatorului este criptată cu funcția „Bcrypt” care folosește algoritmul criptografic Blowfish. Figura 9 În urma criptării adresa de e-mail, numele și parola criptata sunt introduse într-un obiect de tip „UserSchema” acesta reprezentând tipul de obiect de care avem nevoie pentru a scrie în colecția „Users” în baza de date. Urmează astfel salvarea noului utilizator în baza de date printr-un request făcut la aceasta. Odată ce acest utilizator a fost creat în baza de date, serverul primește un răspuns care semnalează succesul, iar apoi la rândul său transmite aplicației React că operația de creare a contului s-a terminat cu succes iar utilizatorul poate fi redirecționat la pagina de autentificare. c. Componente folosite la crearea unui cont – Biblioteca „axios” pentru gestionarea requesturilor de tip HTTP. Axios este o bibliotecă JavaScript care ajută programatorii la crearea acestor requesturi și la gestionarea răspunsurilor. – Componentele de tip „Form”, „Button” și „Alert” din biblioteca publică react-bootstrap pentru crearea elementelor de UI. – Componenta „Link” din biblioteca „react-router-dom” pentru a gestiona link-ul de autentificare. – Functia „bcrypt” creată de Niels Provos și David Maziès și implementată apoi în JavaScript. II. Autentificarea a. Front End Odată ajuns pe pagina de autentificare a aplicației utilizatorului i se va afișa pe ecran modalul corespunzător, acesta conține două elemente de tip imput pentru adresa de e-mail respectiv pentru parolă.
16 Figura 10 Utilizatorul va introduce datele necesare iar apoi va apăsa butonul „Login”. Odata apăsat acest buton va trimite un request HTTP de tip POST care conține datele introduse de utilizator către ruta „api/auth/login” și va aștepta un răspuns de la server. În cazul în care datele sunt corecte răspunsul va conține un token care va fi stocat în memoria browser-ului iar utilizatorul va fi redirectat la pagina principală a aplicației, în caz contrar utilizatorul va fi înștiințat că datele introduse sunt greșite. Token-ul pentru autentificare este valabil timp de o zi. Atunci când utilizatorul accesează aplicația validitatea acestui token este verifica de către aplicație printr-un request la ruta „api/auth/verify” a serverului. în cazul în care token-ul este încă valabil utilizatorul va fi redirecționat la pagina principală a aplicației. b. Back End Odată ajuns request-ul la back end utilizatorul este căutat în baza de date după e-mail. Figura 11 Dacă utilizatorul este găsit în baza de date datele acestuia sunt aduse la server unde parola introdusă de acesta este comparată cu parola criptată și salvată în baza de date. Modul de verificare este prin criptarea parolei introduse și apoi compararea acesteia cu criptarea din baza de date. Figura 12
17 După ce aceasta verificare este trecută serverul va trece la generarea token-ului pentru autentificare. Acest token este unic.
Figura 13 Odată generat token-ul este trimis înapoi la front-end. În cazul în care utilizatorul deja posedă un token stocat în browser acesta este verificat pe server și apoi rezultatul acestei operații este întors către front end. Figura 14 c. Componente folosite pentru autentificare – Biblioteca „JWT” pentru generarea token-urilor și verificarea acestora – Obiectul Cookie pentru stocarea în browser a token-ului și a e-mail-ului – Biblioteca „react-router-dom” pentru gestionarea rutelor. III. Pagina principală a. Front end Pagina principală a aplicației este formata dintr-o listă de design-uri. La încărcarea acestei pagini aplicația React face un request la server pentru a aduce toate design-urile pe care utilizatorul le-a creat.
18 Figura 15 Lista de design-uri conține 3 coloane diferite. Prima coloană reprezintă titlul design-ului, a doua coloană reprezintă data în care a fost creat design-ul, iar a treia coloană reprezintă butoanele de control ale unui design. Figura 16 Fiecare design din listă poate fi activat și dezactivat, acest lucru se face printr-un request de tip PUT trimis către server care modifică în baza de date starea design-ului. De asemenea fiecare design poate fi șters prin apăsarea butonului delete, acest buton va declanșa trimiterea unui request de tip DELETE către server. Serverul va semnala bazei de date ștergerea acestui element. Când se va primi răspuns de la server, lista de design-uri din interfața va fi actualizată. – Activarea/ dezactivarea: Figura 17 – Ștergerea unui design:
Figura 18
19 De asemenea pagina principală adaugă barei de navigare două elemente. Mai întâi adaugă unul de tip input prin care un utilizator poate căuta un design deja creat prin scrierea titlului acestuia în interiorul acestui câmp, iar apoi adaugă un buton care are scopul de a porni procesul de creare a unui nou design. Câmpurile adăugate în bara de navigare: Figura 19 Lista filtrată:
Figura 20 b. Back end Back end-ul specific paginii principale constă în endpoint-urile pentru aducerea design-urilor, pentru activarea și ștergerea lor. Pentru aducerea design-urilor serverul face o interogare a bazei de date folosindu-se de e-mailul utilizatorului care este transmis de către aplicația de front-end. Pentru operațiunea de ștergere serverul are nevoie ca aplicația de React să îi furnizeze în request e-mailul utilizatorului și numele design-ului ca parametri în corpul request-ului. Serverul semnalează bazei de date elementul ce trebuie șters. Odată șters serverul va primi confirmarea de la baza de date apoi va interoga baza de date pentru a obține lista de design-uri rămase și pentru a o întoarce la front end. – Ștergerea pe server: Figura 21 Pentru operațiunea de activare și dezactivare a unui design este nevoie de asemenea adresa de e-mail a utilizatorului și de numele design-ului. Odată primite serverul va schimba câmpul „active” al design-ului din baza de date din „true” în „false” sau invers. – Activarea și dezactivarea pe server:
20 Figura 22 c. Componente folosite pentru pagina principală – Componentele „ListGroup”, „InputGroup”, „Button”, „Modal” din biblioteca „react-bootstrap” – Componentele „MdDeleteForever” și „MdPlayArrow” din „react-icons” IV. Procesul de editare a. Front End Procesul de editarea a paginii unui utilizator începe prin apăsarea butonului „Create Design” prezent în pagina principală a aplicației. Odată apăsat pe ecran se va afișa un modal cu un câmp de tip input. În acest câmp utilizatorul va trebui să introducă URL-ul paginii web personale, după ce acesta a introdus adresa, utilizatorul apasa butonul „create” prezent în modal pentru a trece la pasul următor. În acest moment utilizatorul va fi redirecționat la pagina editor-ului. Figura 23 Odată ajuns pe pagina editorului pagina web a utilizatorului va fi încărcata într-un element de tip „iframe”. Alături de pagina încărcata în iframe se va afișa o componentă care conține opțiunile de editare pe care editorul le oferă. Deasupra acestor opțiuni se afla un câmp de tip input în care utilizatorul trebuie să introducă titlul noului design, iar împreuna cu acest câmp exista două butoane unul pentru salvarea schimbărilor și unul pentru închiderea editorului.
21 Figura 24 Utilizarea editorului decurge în următorul mod: • Utilizatorul poate vedea elementul peste care trece cu mouse-ul prin evidențierea acestuia cu o ramă roșie. Aceasta ramă este adăugată fiecărui element de prin trimiterea unui mesaj la pagina încărcată în iframe. Element peste care trec cu mouse-ul: Figura 25 • Utilizatorul selectează un element prin a da click pe acesta. Atunci când acest eveniment are loc rama elementului va lua culoarea albastră și va persista până când alt element este selectat. Element selectat: Figura 26 • După selectarea unui element utilizatorul trebuie să selecteze una dintre opțiunile prezente în dreapta paginii încărcate. Odată selectată o opțiune un modal specific se va deschide. • Tipuri de modificări prezente:
22 o Background Change Tipul de modificare „background change” deschide un modal deasupra aplicației. în acest modal este prezent un element care permite utilizatorului să aleagă o culoare pe care ar dori să o aplice asupra fundalului elementului selectat.
Figura 27 Odată selectată o culoare utilizatorul este nevoit să apese butonul „Save changes” pentru a salva modificările. în cazul în care utilizatorul se răzgândește acesta poate apăsa butonul „Close” sau elementul de tip „overlay” pentru a închide modalul. Modificările odată salvate sunt transmise de către modal elementului părinte. Modul de transmitere a acestor date este realizat prin pasarea unei funcții de la componenta părinte la componenta copil prin intermediul obiectului de tip „props” specific componentelor din React. Când elementul părinte primește modificările acesta folosește metoda menționată mai sus pentru a transforma input-ul într-un obiect de tip JSON și pentru a trimite un mesaj către pagina web încărcată în iframe ca apoi să fie aplicate. Aceasta transmitere se realizează printr-un „post-message”. De asemenea elementul părinte adaugă modificarea într-o listă de modificări pentru a le afișa pe ecran și pentru a le salva mai târziu în baza de date. Metoda de standardizare, comunicare cu iframe și salvare a modificării în memoria aplicației:
23 Figura 28 o Inject JavaScript Tipul de modificare „inject javascript” deschide un modal care conține un element de tip „textarea”. În acest caz utilizatorul trebuie să introducă un cod în limbajul JavaScript ce urmează să fie rulat în pagina web. Modul de transmitere este asemănător cu cel menționat anterior, o funcție este injectata în modal care se ocupa apoi de standardizarea obiectului și de transmiterea către pagina web a utilizatorului. Atunci când modificările vor fi trimise către iframe, codul injectat de către utilizator va fi rulat imediat iar efectul va fi vizibil în iframe. În cazul în care codul este greșit modificările nu vor putea fi văzute și o eroare va putea fi observată în consola browser-ului.
Figura 29 o Change text
24 Tipul de modificare „change” text poate fi utilizat pentru schimbarea textului unui element din pagină. Modalul pentru schimbări conține de asemenea un element de tip textarea care conține textul deja existent în interiorul elementului. Odată salvată modificarea o metodă asemănătoare celor prezentate mai sus o adaugă în lista de modificări și transmite textul schimbat către iframe. o Change HTML Tipul de modificare „change HTML” este asemănător cu modificările de tip „change text” acesta deschide un modal asemănător, diferența fiind dată doar de către titlul modal-ului și de elementul de tip textarea care este populat cu codul HTML prezent în elementul selectat. Exemplu pentru modulurile cu element de tip textarea:
Figura 30 Odată aplicat elementele noi sunt vizibile în iframe. o Insert CSS class Tipul de modificare „insert CSS class” asemenea tipurilor de modificari anterioare deschide un modal cu un câmp textarea în care utilizatorul poate scrie cod în forma unei clase de CSS care apoi va fi aplicată asupra elementului selectat. o Resize Element Tipul de modificare resize presupune deschiderea unui modal care conține două elemente de tip „input text” unul pentru lățime și unul pentru lungimea elementului. În aceste câmpuri utilizatorul este nevoit
25 să introducă un număr care va reprezenta apoi valoarea lățimii si înălțimii elementului. Asemeni tipurilor de modificări anterioare valorile introduse sunt standardizate într-un obiect, trimise către iframe și salvate în lista de modificări. Exemplu Modal Resize
Figura 31 • Schimbări vizibile în iframe:
Figura 32 • După alegerea modificărilor utilizatorul trebuie să introducă un titlu pentru noul design, iar apoi să apese butonul „save changes” Figura 33 • Odată ce butonul a fost apăsat acesta va declanșa metoda care urmează să creeze un obiect de tip design ce va fi transmis către server. • Alături de modificările făcute de utilizator obiectul va conține adresa de e-mail, numele noului design, câmpul „active” trecut ca „false” și data la care acest design a fost creat.
26 • Odată creat acest obiect este transmis printr-un request de tip HTTP la serverul de NestJS. Metoda de salvare:
Figura 34 • Serverul va răspunde cu lista actualizată, iar interfața se va reafișa cu schimbările făcute. • Tot ce trebuie să mai facă utilizatorul în acest moment este să activeze design-ul din listă. b. Back End Procesul de editare pe partea de back end constă în gestionarea requesturilor de creare și de salvare a datelor în baza de date. Serverul de NestJS primește datele de la front-end și apoi creează obiectul DesignSchema necesar. În final inserează noul obiect în baza de date. Metoda din controller care primește requestul:
27 Figura 35 Metoda care creează și face inserarea în baza de date:
Figura 36 Exemple de design-uri salvate în baza de date:
Figura 37
28 V. Comunicarea cu pagina utilizatorului a. Implementarea Pentru a folosi editorul este nevoie ca utilizatorul să descarce de pe pagina de „guide” din aplicația de front-end fișierul „communication.js”. După ce este descărcat acest fișier JS trebuie inclus în elementul de tip „HEAD” din toate paginile aplicației web a utilizatorului. În cazul în care aplicația web a utilizatorului este de tip single-page application fișierul trebuie introdus în fișierul HTML principal.
Figura 38 b. Gestionarea evenimentului „mouse over” Fișierul communication.js adaugă un listener peste tot obiectul „document” pentru a înregistra elementele „mouseover”. Acest listener generează calea elementului în DOM apoi creează un obiect în care pune tipul evenimentului și calea către element. Odată creat acest obiect este trimis către „window.parent” care în contextul unui iframe este pagina web părinte.
Figura 39 Odată ce editorul primește acest mesaj aplicația React trimite înapoi un mesaj care semnalizează paginii utilizatorului că elementul trebuie să fie accentuat. Obiectul primește astfel o clasă specială de CSS creată dinamic de către fișierul communication.js.
29 Crearea acestei clase este făcută prin generarea unui element de tip „style”, acestui element i se adaugă tipul „text/css”. În interior se adaugă o clasă de CSS, iar apoi elementul este adăugat în elementul „HEAD” al paginii. Figura 40 c. Gestionarea evenimentului „click” pentru selectarea unui element Asemenea evenimentului „mouse over”, gestionarea evenimentului „click” generează calea către elementul selectat. După ce calea a fost generată elementul este căutat iar codul din interiorul său este serializat și păstrat în proprietatea innerHTML. Serializarea este realizată prin biblioteca XMLSerializer din JavaScript. Textul interior al unui element este luat din proprietatea innerText. In final toate aceste date sunt standardizate într-un mesaj care este apoi trimis către pagina părinte.
Figura 41 d. Găsirea căii către element Pentru a găsi calea către un element am creat metoda „getPath” aceasta metodă primește ca input un element și un vector fără elemente. Calea este căutata recursiv apelând proprietatea parentElement a elementului, odată ce ajungem la elementul „body” ne întoarcem din stivă. La fiecare pas căutam tipul elementului și filtram elementele de pe același nivel cu el care nu au același tip din moment ce o cale în DOM are forma „div/div[2]/p” unde „div[2]” este al treilea element de tip div dintre copiii
30 elementului părinte. După aceea căutam indexul elementului de la nivelul curent în vectorul fraților lui. După ce am găsit indexul și am creat elementul de tip „elementType[index]” adăugam acest element la vectorul primit prin referință la început. Acest pas se repetă pentru fiecare nivel al stivei. La final înainte să trimitem calea către editor aplicam operația „join” asupra vectorului și împreunăm elementele folosind separatorul „/” pentru a transforma vectorul într-un string.
Figura 42 e. Găsirea unui element folosind calea creată Pentru a găsi un element folosind calea creată anterior primim folosim metoda getElementByXpath care primește ca input stringul generat anterior. Acum separam string-ul într-un vector de string-uri cu separatorul „/”. Aplicam reguli de parsare asupra fiecărui element din vector și salvam elementele într-un nou vector. Căutarea elementului pornește de la elementul „body” al paginii și coboram pe arbore în funcție de numele elementului căutat sau în funcție de numele și indexul elementului căutat.
31 Figura 43 La finalul metodei întoarcem o referință la elementul găsit. f. Gestionarea mesajelor primite de la editor Pentru a gestiona mesajele primite de la editor adăugam un listener care să proceseze toate mesajele primite. Când primim un mesaj mai întâi verificam originea mesajului, dacă mesajul vine de la editor atunci îl procesăm, dacă nu trecem mai departe. Dacă mesajul conține evenimentul de tip „mouseover” atunci adăugam clasa CSS creată la elementul peste care utilizatorul trece cu mouse-ul. în cazul în care mouse-ul iese din element clasa este ștearsă din lista de clase CSS a elementului. Adăugarea clasei: Figura 44
32 Ștergerea clasei din lista: Figura 45 Dacă mesajul conține evenimentul de tip „click” atunci adăugam la atributul „style” al elementului rama albastră de selecție. Înainte să adăugăm această proprietate ștergem rama de pe fostul element care a fost selectat. Adăugarea ramei albastre: Figura 46 Ștergerea ramei de pe fostul element selectat: Figura 47 Dacă mesajele sunt de tip modificare verificăm care este tipul acestei modificări și pentru fiecare dintre ele gestionăm proprietățile primite în mod diferit:
Figura 48
33 g. Gestionarea modificărilor: i. Background change Pentru schimbarea de tip background change este folosită proprietatea style a elementului. Figura 49 ii. JavaScript Injection Pentru injecție de cod JS mai întâi creăm un nou element de tip script iar apoi adăugam în interiorul acestui element nou creat codul care a fost scris de către utilizator. La final adăugam elementul creat în interiorul elementului „head”. Figura 50 iii. Change Text Schimbarea de text se folosește de proprietatea innerText a unui element. Textul inserat de utilizator este pus în această proprietate. iv. CSS Class Injection Injecția de CSS este realizată la fel ca și crearea clasei pentru „mouseover” singura diferență fiind reprezentată de proprietatea innerText a elementului creat. v. HTML Injection Pentru adăugarea codului HTML creăm un element de tip „template” și adăugam apoi în interiorul lui codul scris de către utilizator. La finalul metodei întoarcem copiii elementului „template” prin proprietatea childNodes. După întoarcerea acestor elemente transformăm HTMLCollection în tipul Array din JavaScript și adăugam pe rând toate elementele în elementul selectat. vi. Resize
34 Operațiunea de resize se folosește de proprietățile styles.width și styles.height în care introduce valorile alese de utilizator. h. Gestionarea design-urilor active Ca pagina web a utilizatorului să aplice design-urile active aceasta face un request de tip GET utilizând biblioteca XMLHttpRequest din javascript care este comună tuturor fișierelor JS. Requestul merge la serverul de NestJS care întoarce lista de design-uri active. Odată finalizat request-ul programul trece prin toate design-urile aduse și aplică pe rând modificările folosind metodele descrise mai sus.
Figura 51 VI. Introducere a „react hooks” Conceptul de „hooks” a fost introdus în versiunea 16.8 a frameworkului „React”. Cea mai importanta adiție, din punctul meu de vedere, este introducerea opțiunii utilizării „state-ului” a unei componente fără ca aceasta componentă să fie de tip „class”.
35 Înainte pentru a crea o componentă „stateful” era nevoie să se declare o clasă iar ca state-ul să se schimbe trebuiau folosite metode specifice numite „lifecycle hooks” (a nu se confunda cu React Hooks ). Exemple de lifecycle hooks ar fi metode precum „componentDidMount” și „componentDidUpdate”. Astfel de metode ajungeau să conțină multe bucăți de logică care nu avea legătura între ele. Un exemplu simplu ar fi lansarea unui request pentru a aduce un set de date precum în componenta „design list” precum și adăugarea unui „listener” care gestionează un eveniment, ambele ar fi trebuit adăugate în „componentDidMount”. Folosind hook-uri acum putem despărți aceste cazuri si putem modulariza mai bine codul. Hook-urile folosite de mine în aplicație au fost „useState” și „useHistory”. Hook-ul useState a fost folosit pentru a gestiona starea unei componente, câteva exemple ar fi reprezentate de stocarea unui input primit de la tastatura: Inițializarea câmpurilor state-ului: Figura 52 Hook-ul useHistory va fi prezentat în secțiunea de gestionare a rutelor aplicației. VII. Gestionarea rutelor Din moment ce front end-ul este o aplicație de tip single-page în realitate exista o singura pagina care este încărcata. Pentru a da utilizatorului impresia unei aplicații web cu mai multe pagini avem nevoie să gestionam rutele aplicației și componentele care sunt afișate pe ecran. Pentru a gestiona rutele aplicației folosim biblioteca „react-router-dom”. Aceasta bibliotecă ne permite să folosim componentele precum: „Router”, „Route”, „Redirect” care ne ajuta la afișarea condiționata a componentelor react ale interfeței. Figura 53 Cum se poate observa în imaginea anterioară componentele de tip „Route” primesc ca parametrii un „path” care le semnalează calea pe care sunt afișate și un „component” care reprezintă componenta ce trebuie afișată.
36 De asemenea o componentă de tip „Route” poate primi ca și copil o componentă de tip „Redirect” care redirecționează utilizatorul la calea specificată în parametrul „to”. Toate aceste componente, pentru a fi valide, trebuie să fie copii ai elementului „Router”. De asemenea pentru redirecționarea utilizatorului în diferite cazuri cum ar fi prezenta unui token valid în cookie-urile browser-ului am mai folosit hook-ul „useHistory” care îmi permite să manipulez istoria browser-ului. Exemplu de redirecționare folosind Hook-ul useHistory: Figura 54 VIII. Algoritmul de criptare Blowfish și functia Bcrypt a. Algoritmul Blowfish Funcția „bcrypt” menționată mai sus folosește la baza algoritmul Blowfish creat de către Bruce Schneier în 1993 cu scopul de a înlocui algoritmul DES. Securitatea acestui algoritm a fost testată și demonstrată de multe ori de la apariția lui iar o criptare totală cu Blowfish nu a fost niciodată spartă. Blowfish este de asemenea foarte rapid, făcând algoritmul potrivit pentru a fi folosit în aplicații desktop sau mobile. Modul de funcționare • Blowfish este un algoritm cu cheie de lungime variabila cu blocuri de 64 de biti. Algoritmul constă în 2 părți: o expansiune a cheii urmată de criptarea datelor. Expansiunea cheii constă în transformarea unei chei cu maxim 448 de biți în mai multe șiruri de subchei care au în total 4168 bytes. Encriptarea datelor se realizează prin utilizarea unei rețele Feistel în 16 iterații. Fiecare iterație constă într-o permutare dependentă de cheie și o substituție bazată pe cheie și dată. Toate operațiunile sunt de tip XOR și adunări pe 32 de biți. • Subchei: Blowfish folosește un număr mare de subchei. Aceste chei trebuie să fie pregătite înainte de orice criptare sau decriptare. P-șirurile constau în 18 subchei de 32 de biți P1, …, P18. Sunt patru S-box-uri de 32 de biți cu 256 de entry-uri. În total 521 de iterații sunt necesare pentru a genera toate subcheile. • Criptarea:
37 o Inputul este un element de 64 de bițI X. o Împarte X în două jumătăți de 32 de biți xD, xS. o Pentru fiecare iterație: § xS = xS XOR Pi § xD = F(xS) XOR xD § Interschimbă xD și xS § Treci la următoarea iterație o End LOOP o Interschimbă xD și xS o xD = xD XOR P17 o xS = xS XOR P18 o Recombină xS și xD o Decriptarea se face la fel ca și criptarea doar că P1, …, P18 sunt luate în ordine inversă. o Reprezentare grafică a algoritmului Blowfish
Figura 55 Concluzii Blowfish este un cifru rapid pe blocuri, exceptând cazul schimbării cheilor. Fiecare nouă cheie necesită preprocesarea echivalentă a criptării a 4 kilobytes de text, ceea ce este foarte încet comparativ cu alte cifruri de bloc. Acest lucru reprezintă un dezavantaj în unele aplicații, însă schimbarea lentă a cheilor și efortul computațional oferă protecție împotriva atacurilor pe bază de dicționar (dictionary attack). [XIV, XXVI]
38 b. Funcția Bcrypt Funcția bcrypt a fost creată în anul 1999 cu scopul de a stoca parola într-un mod sigur. Înafara de folosirea unui salt pentru a proteja împotriva atacurilor de tip „rainbow table” funcția bcrypt fiind adaptivă. Numărul de iterații poate fi crescut acest lucru făcând-o mai înceata pentru a rezista în fața atacurilor de tip „brute force” odată cu creșterea în puterea de calcul a computerelor. [XXVIII]
39 Concluzii Din punctul meu de vedere această aplicație reușește să atingă obiectivele propuse la începutul lucrării. Opțiunile de editare în acest moment sunt limitate dar acestea ar putea fi extinse odată cu continuarea dezvoltării aplicației. În momentul de fața sunt implementate puține opțiuni dedicate unui utilizator fără cunoștințe tehnice, dar chiar și așa un utilizator poate modifica o pagina web fără prea mari cunoștințe tehnice. In același timp sunt de părere că aceasta aplicație demonstrează eficiența tehnologiilor web moderne și cum ele pot interacționa între ele. Aplicația poate fii îmbunătățita prin adăugarea de noi funcționalități precum editarea altor proprietăți de tip CSS fără a fi nevoie de scrierea codului. In final sunt mulțumit de aceasta tema și consider că prin intermediul ei am reușit să îmi extind cunoștințele in domeniul tehnologiilor web și cum pot fi ele aplicate. De asemenea aceasta a fost pentru mine prima oportunitate de a lucra cu servicii cloud precum cele furnizate de Amazon.
40 Bibliografie I. https://www.udemy.com/course/react-the-complete-guide-incl-redux/ II. https://www.udemy.com/course/nestjs-zero-to-hero/ III. https://react-bootstrap.github.io/ IV. https://reactjs.org/ V. https://stackoverflow.com/ VI. https://sass-lang.com/ VII. https://medium.com/ VIII. https://docs.nestjs.com/ IX. https://react-icons.github.io/react-icons/icons?name=md X. https://aws.amazon.com/education/awseducate/ XI. https://www.youtube.com/ XII. https://nrwl.io/ XIII. https://hackernoon.com/angular-vs-react-vs-vue-which-is-the-best-choice-for-2019-16ce0deb3847 XIV. https://www.geeksforgeeks.org/blowfish-algorithm-with-examples/ XV. https://reacttraining.com/react-router/web/guides/quick-start XVI. https://nx.dev/react XVII. https://www.mongodb.com/cloud/atlas XVIII. https://app.diagrams.net/ XIX. https://www.w3schools.com/ XX. https://github.com/axios/axios XXI. https://lifesaver.codes/ XXII. https://www.dev2qa.com/how-to-run-node-js-server-in-background/ XXIII. https://labs.vocareum.com/main/main.php?m=editor&nav=1&asnid=14334&stepid=14335 XXIV. https://dev.to/antogarand/deploying-a-nestjs-application-on-aws-beanstalk-4no1 XXV. https://classic.yarnpkg.com/en/docs/install#mac-stable XXVI. Proiect Criptografie si Securitate ( Împreună cu Andreea Panait, Alexandru Brinzea, Cătălin Spătaru si Ina Țencu) XXVII. https://www.oreilly.com/library/view/programming-javascript-applications/9781491950289/ch01.html XXVIII. https://www.wikipedia.org/
Copyright Notice
© Licențiada.org respectă drepturile de proprietate intelectuală și așteaptă ca toți utilizatorii să facă același lucru. Dacă consideri că un conținut de pe site încalcă drepturile tale de autor, te rugăm să trimiți o notificare DMCA.
Acest articol: 1 UNIVERSITATEA DIN BUCUREȘTI FACULTATEA DE MATEMATICA ȘI INFORMATICĂ SPECIALIZAREA INFORMATICĂ Lucrare de licență APLICAȚIE WEB DE EDITARE A… [603887] (ID: 603887)
Dacă considerați că acest conținut vă încalcă drepturile de autor, vă rugăm să depuneți o cerere pe pagina noastră Copyright Takedown.
