As we wrote, the frontend of our own hosting control panel: framework and backdoors



In the last article, we talked about how we came up with the idea of ​​writing our own hosting control panel and about the general structure of the finished panel.



Today our front-end developer Artysh will tell how he wrote the front-end of this panel: which framework was chosen, which antipattern is considered good form and how to protect yourself from backdoors if you use ready-made libraries.



Framework choice: why were you looking for a new one



The previous panel was implemented on its own framework written in jQuery. We sat on VMManager, it required a lot of improvements: in terms of interface and functionality, it was hard to maintain such code. Adding new functionality to the panel from the front took a long time. It’s clear that if you wish, you can implement a good framework on jQuery (I still love jQuery) or even a semblance of CMS, but this was not the best option: starting with scant documentation on a self-written framework and ending with the not entirely correct architecture of the application itself.



The old panel was implemented as a Single Page Application, and this was where its good qualities ended. After solving another puzzle to add a button to the list, I realized that I needed an alternative. The choice fell on Vue.



Why SPA?



Single Page Application is an ideal choice for a control panel. The control panel in terms of rendering is quite a simple thing, this work can be easily entrusted to the user's browser. In addition, SEO optimization is not important for the panel, for this we have a main site. Well, users of the panel perceive the required time for the initial loading of all necessary scripts due to the specifics of these users themselves. Again, the backend we got was a classic RestAPI service - to provide an open API to our customers in the future.



The SPA application turned out to be so light that it works well with the browser of phones and tablets - we just did adaptive layout and we did not have to create a separate application.



Why Vue?



3 years ago Vue was a relatively young framework, but even then they talked and wrote a lot about it, and when the release of version 2.0 came out, we decided to bet on it - and we were right. At first they planned to just gradually replace some components written in jQuery and Vue made it easy to do. But then, after rather voluminous components were rewritten, they decided that it would be better to rewrite the entire application to Vue.

This would be a risky step and we decided to take it for 4 reasons:



  1. Vue is a simple declarative framework, even coders can understand it. If anything, it’s easy to find a developer for him or just teach a friend. So, we will have no problems finding a new developer and entering the project if a tram crosses me (praise to the gods, there are none in my city).
  2. Vue is objectively good for writing SPA applications.
  3. I had the experience of developing React before my eyes and I suggested that the popularity of Vue will grow as well. Now the framework is included in the TOP-3 of popular JS frameworks (this is easy to check with a search query), second only to React and Angular. He has good support, a developed ecosystem and a large community.
  4. Development speed. Personally, I immediately began to perceive Vue as a kind of constructor and development on it goes pretty quickly: if I need, for example, a date picker, most likely on Vue it already exists, is free to use and tested by the community. I just install the component in the project, write a tag and everything works. In fact, our panel consists of 70-80% of the finished libraries. I mean the use of the component, not the size of the code base, which can be checked with a command like: npx intrinsic / loc


When implementing a project, you always take into account its prospects, especially development prospects. And the fact that Vue ecosystem already has such tools as Weex, Quasar Framework or Nuxt for me significantly expand the horizons of our panel development.



On Habré there is a wonderful article about Vue from its creator, and I will talk about some features of our application.



Vuex Sync with RestAPI Service



Part of the Vuex global storage data in our application is synchronized with RestAPI by means of ordinary requests at the corresponding addresses. Why did we do this? Well, at least so that the main user settings are not tied to a specific browser of a particular device. You can enter our panel from your wife’s computer or from a game club and at the same time get into the same familiar environment as you had in your own car.



In addition, when synchronization was only with localStorage, some browsers lost the contents of localStorage during updates - it was completely deleted. Yes, and recently there has been a tendency to tighten the policy of storing user data in cookies, for example, a function in WebKit Intelligent Tracking Prevention - for an hour they will get to localStorage.



Event bus



Yes, we use the global event bus. As in any other large application with many components, sooner or later there is a need to establish interaction between unrelated components. Even through global storage. It is clear that if there is a parent-child relationship, their interaction is standardly organized through the props properties in one direction and the $ emit method in the other, or through storage, as described in the Vue recommendations .



But the documentation also describes the possibility of using the global event bus . We have a bunch of forms in the project with different sets of fields and in some cases (there are few of them, but all of them are fundamental) you need to somehow react in a special way to changing the field value. It does not make sense to store the values ​​of all fields of each form in the global storage:



  1. Firstly, because of the rare need
  2. Secondly, all our forms are dynamically generated and the set of fields for any form can change dramatically.


So I decided to use the event bus mechanism. At the same time, nothing prevents you from using your Event emitter - the main thing is to use this mechanism carefully, only for exceptional situations and carefully clean up everything for yourself.



RestAPI interaction with the panel



To make the interface more responsive in the old jQuery framework, the feedback from RestAPI to the client application was emulated through a tricky timer system: it ran RestAPI polls at a certain interval and redrawed the DOM nodes that affected the changes.



This was not an ideal solution: in all modern browsers, timers freeze almost completely when the tab becomes inactive and gets a low priority. As a result, a request to the RestAPI service may be delayed and receive already irrelevant data.



To solve this problem in a new panel, I decided to use a bundle from the Nchan module for the Nginx web server and new features of the HTML5 interfaces - EventSource and WebWorker.



The Nchan module supports sending messages through Websocket, EventSource and Long-Polling. I conducted several tests and decided to use EventSource: messages can only be text and messages flow only in one direction (from the server). This completely solved the task.



Now the EventSource interface operates in a separate WebWorker background thread, regardless of the activity of the tab. In the same thread, a primitive message queue is organized so that nothing is lost. The queue is sent to the main thread of the application, which in turn produces the necessary redraws of the interface when it is convenient and allows the browser.



Backdoors: how and why I check component security



Before connecting the library, it is mandatory to check it for safety: there was a case when a component specifically introduced a backdoor, which allowed accessing the site and downloading data.



But more often security holes appear more likely due to sloppiness of developers. There is a team in application markets that checks components for security, but it’s not too toothy and it’s better to check libraries manually.



I always check packages for preinstall, install, and postinstall hooks in the “scripts” field of the “package.json” file. In addition, I use static package analyzers such as retire , snyk and the “audit” command of the npm package manager.



Security warnings come in different levels, most often when you run non-critical checks. Sometimes, in order to treat a library, it is enough to upgrade - the library developers themselves monitor the security.



If a library once compromised itself, it is better to replace it - this is a sign of unreliability, so with warnings I choose to look for another library.



After the package has passed the analysis, I will definitely fix its version. If you need a different version - the package passes the analysis again. Yes, it takes time, but it's worth it.



So far, backdoors have never come to us for production.



Many many comments



As I said, Vue was chosen for its simplicity and declarativeness. In addition to this, I write a lot of comments on almost every line: so that in which case the new developer can easily enter the project and so that I myself easily return to the old pieces of code.



Why I fell in love with the new frontend and the panel as a whole



It has become easier to maintain code



Development took half a year. Now I am more likely to support the panel, my code does not press and does not rub.



Customers can quickly get what they requested.







It became fast and convenient to add new features that appeared in the backend: for example, I added payment for legal entities in 2 days, snapshots in 1 day.



I am open to questions



In this article, I revealed some of the secrets associated with the frontend of our panel. If you have any questions - welcome to comment, I will try to answer.



And, of course, I invite you to express suggestions for improving the panel.



All Articles