Research
Security News
Malicious npm Packages Inject SSH Backdoors via Typosquatted Libraries
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
@gravity-ui/app-layout
Advanced tools
npm install --save-dev @gravity-ui/app-layout
With express
:
import express from 'express';
import {createRenderFunction} from '@gravity-ui/app-layout';
const app = express();
const renderLayout = createRenderFunction();
app.get('/', function (req, res) {
res.send(
renderLayout({
// RenderParams
title: 'Home page',
bodyContent: {
root: 'Hello world!',
},
}),
);
});
app.listen(3000);
where
interface RenderParams<Data, Plugins> {
// Any json compatible data, will be set to window.__DATA__ on the page
data?: Data;
// favicon
icon?: Icon;
// nonce to be set on the appropriate tags
nonce?: string;
// common options
// Page title
title: string;
// language of page, will be set to html tag
lang?: string;
isMobile?: boolean;
// html attributes
htmlAttributes?: string;
// header tag content
// meta tags
meta?: Meta[];
// link tags
links?: Link[];
// script tags
scripts?: Script[];
// style tags
styleSheets?: Stylesheet[];
// script tags with inlined code
inlineScripts?: string[];
// style tags with inlined styles
inlineStyleSheets?: string[];
// content of body tag
bodyContent?: {
// class name for body tag
className?: string;
// body attributes
attributes?: string;
// body content before div tag with id root
beforeRoot?: string;
// innerHtml content of div tag with id root
root?: string;
// body content after div tag with id root
afterRoot?: string;
};
// plugins options
pluginsOptions?: Partial<PluginsOptions<Plugins>>;
}
Describes meta
tag:
interface Meta {
name: string;
content: string;
}
Example:
const meta = [
{name: 'description', content: 'some text'},
{name: 'robots', content: 'noindex'},
{name: 'og:title', content: 'Some title'},
];
Will be rendered as:
<meta name="description" content="some text" />
<meta name="robots" content="noindex" />
<meta property="og:title" content="Some title" />
Describes page favicon:
interface Icon {
type?: string;
sizes?: string;
href?: string;
}
Default value is:
const icon = {
type: 'image/png',
sizes: '16x16',
href: '/favicon.png',
};
Describes link
tag:
interface Link {
as?: string;
href: string;
rel?: string;
type?: string;
sizes?: string;
title?: HTMLLinkElement['title'];
crossOrigin?: '' | 'anonymous' | 'use-credentials';
}
Example:
const link = {
href: 'myFont.woff2',
rel: 'preload',
as: 'font',
type: 'font/woff2',
crossOrigin: 'anonymous',
};
will be rendered as:
<link href="myFont.woff2" rel="preload" as="font" type="font/woff2" crossorigin="anonymous" />
Describes link to script with preload:
interface Script {
src: string;
defer?: boolean;
async?: boolean;
crossOrigin?: '' | 'anonymous' | 'use-credentials';
type?: 'importmap' | 'module' | string;
}
Example:
const script = {
src: 'url/to/script',
defer: true,
async: false,
crossOrigin: 'anonymous',
};
will be rendered as:
<link href="url/to/script" rel="preload" as="script" crossorigin="anonymous" />
<script src="url/to/script" defer="true" async="false" crossorigin="anonymous" nonce="..."></script>
Describe link to styles:
interface Stylesheet {
href: string;
}
Example:
const styleSheet = {
href: 'url/to/stylesheet',
};
will be rendered as:
<link href="url/to/stylesheet" rel="stylesheet" />
Render function can be extended by plugins. Plugin may rewrite user defined render content.
Plugin is an object with name
and apply
properties:
interface Plugin<Options = any, Name = string> {
name: Name;
apply: (params: {
options: Options | undefined; // passed through `renderLayout` function in `pluginsOptions` parameter.
commonOptions: CommonOptions;
renderContent: RenderContent;
/** @deprecated use `renderContent.helpers` instead */
utils: RenderHelpers;
}) => void;
}
interface CommonOptions {
name: string;
title: string;
lang?: string;
isMobile?: boolean;
}
export interface HeadContent {
scripts: Script[];
helpers: RenderHelpers;
links: Link[];
meta: Meta[];
styleSheets: Stylesheet[];
inlineStyleSheets: string[];
inlineScripts: string[];
title: string;
}
export interface BodyContent {
attributes: Attributes;
beforeRoot: string[];
root?: string;
afterRoot: string[];
}
export interface RenderContent extends HeadContent {
htmlAttributes: Attributes;
bodyContent: BodyContent;
}
export interface RenderHelpers {
renderScript(script: Script): string;
renderInlineScript(content: string): string;
renderStyle(style: Stylesheet): string;
renderInlineStyle(content: string): string;
renderMeta(meta: Meta): string;
renderLink(link: Link): string;
attrs(obj: Attributes): string;
}
There are some plugins in this package:
Adds google analytics counter on the page.
Usage:
import {createRenderFunction, createGoogleAnalyticsPlugin} from '@gravity-ui/app-layout';
const renderLayout = createRenderFunction([createGoogleAnalyticsPlugin()]);
app.get((req, res) => {
res.send(
renderLayout({
title: 'Home page',
pluginsOptions: {
googleAnalytics: {
useBeaconTransport: true, // enables use of navigator.sendBeacon
counter: {
id: 'some id',
},
},
},
}),
);
});
Plugin options:
interface GoogleAnalyticsCounter {
id: string;
}
interface GoogleAnalyticsOptions {
useBeaconTransport?: boolean;
counter: GoogleAnalyticsCounter;
}
Adds Yandex metrics counters on the page.
Usage:
import {createRenderFunction, createYandexMetrikaPlugin} from '@gravity-ui/app-layout';
const renderLayout = createRenderFunction([createYandexMetrikaPlugin()]);
app.get((req, res) => {
res.send(
renderLayout({
title: 'Home page',
pluginsOptions: {
yandexMetrika: {
counter: {
id: 123123123,
defer: true,
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
},
},
},
}),
);
});
Plugin options:
export type UserParams = {
[x: string]: boolean | string | number | null | UserParams;
};
export interface MetrikaCounter {
id: number;
defer: boolean;
clickmap: boolean;
trackLinks: boolean;
accurateTrackBounce: boolean | number;
webvisor?: boolean;
nonce?: string;
encryptedExperiments?: string;
triggerEvent?: boolean;
trackHash?: boolean;
ecommerce?: boolean | string;
type?: number;
userParams?: UserParams;
}
export type MetrikaOptions = {
src?: string;
counter: MetrikaCounter | MetrikaCounter[];
};
Adds script and styles from webpack assets manifest file.
Usage:
import {createRenderFunction, createLayoutPlugin} from '@gravity-ui/app-layout';
const renderLayout = createRenderFunction([
createLayoutPlugin({manifest: 'path/to/assets-manifest.json', publicPath: '/build/'}),
]);
app.get((req, res) => {
res.send(
renderLayout({
title: 'Home page',
pluginsOptions: {
layout: {
name: 'home',
},
},
}),
);
});
Plugin options:
export interface LayoutOptions {
name: string;
prefix?: string;
}
Adds body attributes.
Usage:
import {createRenderFunction, createUikitPlugin} from '@gravity-ui/app-layout';
const renderLayout = createRenderFunction([createUikitPlugin()]);
app.get((req, res) => {
res.send(
renderLayout({
title: 'Home page',
pluginsOptions: {
uikit: {
theme: 'dark',
direction: 'ltr',
},
},
}),
);
});
Plugin options:
interface UikitPluginOptions {
theme: string;
direction?: 'ltr' | 'rtl';
}
There is helper to create all plugins:
import {createMiddleware, createDefaultPlugins} from '@gravity-ui/app-layout';
const renderLayout = createRenderFunction(
createDefaultPlugins({layout: {manifest: 'path/to/assets-manifest.json'}})
);
app.get((req, res) => {
res.send(renderLayout({
title: 'Home page',
pluginsOptions: {
layout: {
name: 'home'
},
googleAnalytics: {
counter: {...}
},
yandexMetrika: {
counter: {...}
},
},
}));
})
With parts renderers generateRenderContent
, renderHeadContent
, renderBodyContent
via html streaming:
import express from 'express';
import htmlescape from 'htmlescape';
import {
generateRenderContent,
renderHeadContent,
renderBodyContent,
createDefaultPlugins,
} from '@gravity-ui/app-layout';
const app = express();
app.get('/', async function (req, res) {
res.writeHead(200, {
'Content-Type': 'text/html',
'Transfer-Encoding': 'chunked',
});
const plugins = createDefaultPlugins({layout: {manifest: 'path/to/assets-manifest.json'}});
const content = generateRenderContent(plugins, {
title: 'Home page',
});
const {htmlAttributes, helpers, bodyContent} = content;
res.write(`
<!DOCTYPE html>
<html ${helpers.attrs({...htmlAttributes})}>
<head>
${renderHeadContent(content)}
</head>
<body ${helpers.attrs(bodyContent.attributes)}>
${renderBodyContent(content)}
`);
const data = await getUserData();
res.write(`
${content.renderHelpers.renderInlineScript(`
window.__DATA__ = ${htmlescape(data)};
`)}
</body>
</html>
`);
res.end();
});
app.listen(3000);
FAQs
## Install
We found that @gravity-ui/app-layout demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Security News
Socket’s threat research team has detected six malicious npm packages typosquatting popular libraries to insert SSH backdoors.
Security News
MITRE's 2024 CWE Top 25 highlights critical software vulnerabilities like XSS, SQL Injection, and CSRF, reflecting shifts due to a refined ranking methodology.
Security News
In this segment of the Risky Business podcast, Feross Aboukhadijeh and Patrick Gray discuss the challenges of tracking malware discovered in open source softare.