Invest-currency.ru

Как обезопасить себя в кризис?
0 просмотров
Рейтинг статьи
1 звезда2 звезды3 звезды4 звезды5 звезд
Загрузка...

Google access token

ПрОдАвЕц ИгРуШеК

Когда в адресной книге Google набирается несколько тысяч клиентов, становится тяжеловато ворочать этим объемным списком. Импорт/экспорт в странички Excel становится неудобным; кроме того появляются CRM-подобные приложения, в которых хотелось бы интегрировать самые разные базы данных, в том числе и контакты Google. Значит, пришло время доступиться к нашим контактам через консольные приложения, используя Google Contacts API.

Получение списка контактов

Используя API, мы можем не только получить список контактов, но также и видоизменять и дополнять его. В простейшем случае, первые 150 записей из адресной книги можно вытащить так, вбив это в адресную строку браузера:

Можно догадаться, что данные мы получим в формате json, что понятно, поскольку каждой записи в адресной книге соответствует куча полей, также понятно сколько записей будет выведено. И поскольку здесь нет ни нашего логина, ни пароля, можно предположить, что ACCESS_TOKEN — это та самая строка, которая обеспечивает авторизацию. Чтобы понять, как эта авторизация работает, мне в свое время пришлось выполнить несколько танцев с бубном. В этой статье делюсь результатами своих изысканий.

Регистрируемся в Google

Предполагаю, что у вас уже есть Google-аккаунт, или электронная почта. Логинимся на страничке Гугла и идем по адресу https://console.developers.google.com/cloud-resource-manager , где создаем новый проект. Даем ему произвольное название, например Beerware. Дальше переходим в другое место https://console.developers.google.com/apis/credentials. Жмем кнопочку «Создать учетные данные» и выбираем «Идентификатор клиента OAuth», и дальше отмечаем «Другие типы». Дадим название идентификатору — скажем Beerware Script.

Не спрашивайте меня, что означает разнообразие в выборе различных опций. Погружаться в это можно долго, важно лишь что наш вариант — рабочий.

Это все, что нужно было сделать в девелоперских панелях Гугла. Если вы нажмете на редактирование идентификатора, то увидите ID клиента и секрет клиента. Запомним эти названия, они понадобятся нам дальше. Чтобы не путаться с обозначениями при подстановке в другие строки, обозначим их CLIENT_ID и CLIENT_SECRET.

Authorization Flow: как проходит авторизация OAuth2

Конечной целью авторизации является получение ACCESS_TOKEN, который необходимо использовать каждый раз когда мы делаем запрос к адресной книге. Теперь нам нужно внимательно пройтись по всем этапам. Самая главная вещь, которая толком не описана в документации Google — какие этапы выполняются только один раз, а какие нужно выполнять периодически. Я буду это подчеркивать.

Каждый этап — это обращение к серверу Google по HTTPS и получение ответа. Детали запроса я распишу позже, сейчас главное — уяснить общую схему.

Получение кода авторизации

Код авторизации сразу ставит в тупик. Зачем он нужен, если уже есть CLIENT_SECRET? Разница в том, что код авторизации используется только один раз — для получения токенов. Замечу сразу, что если вы попытаетесь получить по одному и тому же коду авторизации токены еще раз, то получите ошибку. Таким образом, код авторизации действителен пока мы еще не получили токены. После их получения он сразу «протухает». Но об этом — дальше.

CLIENT_SECRET, как и CLIENT_ID — постоянные строки, скрытые в нашем приложении вдали от посторонних глаз.

Итак, посылаем на сервер CLIENT_ID, CLIENT_SECRET и получаем код авторизации. Назовем его AUTH_CODE.

И снова заголовок наводит на размышления. Почему токены во множественном числе, когда вначале говорилось только об ACCESS_TOKEN? На самом деле, помимо этого токена, который используется при работе с адресной книгой, нам дают еще REFRESH_TOKEN. Его роль будет ясна ниже.

Посылаем на сервер CLIENT_ID, CLIENT_SECRET, AUTH_CODE и получаем парочку ACCESS_TOKEN, REFRESH_TOKEN.

Казалось бы, тут можно забыть о REFRESH_TOKEN, поскольку ACCESS_TOKEN у нас в руках, и дальше еще забыть и про авторизацию и спокойно пользоваться ACCESS_TOKEN во всех запросах. Я так поначалу и делал, только обнаружил что в один прекрасный момент сервер перекрыл мне доступ. В чем дело? А причина была в том, что по задумке Google время жизни ACCESS_TOKEN — всего лишь час, после чего он протухает и работать с ним не получится.

Что теперь, снова получать код авторизации и токены? Нет. Про эти два этапа «получение кода авторизации» и «получение токенов» можно полностью забыть и уже никогда к ним не возвращаться. Самое главное, что у нас есть — это REFRESH_TOKEN. Сохраните его в надежном месте, поскольку теперь кроме него нам ничего не нужно.

Замечу, что эти пройденные этапы мы выполняем лично. Наше приложение Beerware Script о них ничего не знает: ему нужны только токены.

Получение ACCESS_TOKEN по REFRESH_TOKEN

Дальше все становится просто. Когда ACCESS_TOKEN протухает, то есть через час становится не действительным, или просто не дожидаясь этого момента, мы посылаем на сервер CLIENT_ID, CLIENT_SECRET, REFRESH_TOKEN и получаем обновленное значение ACCESS_TOKEN, которое используем для запросов к серверу. Важно знать, что при этом REFRESH_TOKEN не меняется. Поэтому для приложения критично запомнить его, например в файле, при получении в самый первый раз.

Все этапы авторизации из командной строки

Для различных языков есть соответствующие библиотеки OAuth2. Мы же, для ясности изложения, все будем делать ручками из командной строки, формируя запросы с помощью утилиты curl. В конце концов, все эти библиотеки делают тоже самое — формируют url запросы к серверу Google.

Начнем с получения кода авторизации. Поскольку эта процедура выполняется только раз, не грех поработать вместо нашего приложения. Вбиваем в адресную строку броузера и наблюдаем:

Создание страницы авторизации с помощью Google OAuth API

Дата публикации: 2019-07-02

От автора: в этой статье я собираюсь объяснить, как интегрировать авторизацию Google на ваш сайт на PHP. Мы будем использовать Google OAuth API, который является простым и мощным способом добавить вход через Google на ваш сайт.

Как веб-пользователь, вы, вероятно, испытывали трудности с управлением различными учетными записями для разных сайтов, в частности, когда у вас есть несколько паролей для разных сервисов, и веб-сайт просит вас создать еще одну учетную запись на их сайте.

Чтобы решить эту проблему, вы можете предложить функцию единого входа, позволяющую посетителям использовать существующие учетные данные для открытия учетной записи на вашем сайте. В настоящее время многие веб-сайты позволяют пользователям входить в систему, используя свои существующие учетные записи в Google, Facebook или в других популярных сервисах. Это удобный способ для новых пользователей зарегистрироваться на стороннем сайте вместо регистрации новой учетной записи с еще одним именем пользователя и паролем.

В этом посте мы будем использовать API авторизации Google OAuth, который позволяет пользователям входить в систему с использованием существующих учетных записей Google. Конечно, пользователи по-прежнему должны иметь возможность зарегистрироваться с помощью обычной формы регистрации на вашем сайте, но предоставление входа через Google или чего-то подобного может помочь сохранить нормальный коэффициент удержания пользователей.

Как работает авторизация Google

Во-первых, давайте разберемся, как работает авторизация через Google на вашем сайте.

Бесплатный курс по PHP программированию

Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC

В курсе 39 уроков | 15 часов видео | исходники для каждого урока

На странице входа в систему вашего сайта пользователи могут выбрать один из двух вариантов входа. Первый — указать имя пользователя и пароль, если у них уже есть учетная запись на вашем сайте. А другой заключается в том, чтобы войти на сайт с помощью существующей учетной записи Google.

Читать еще:  Access control expose headers

Когда они нажимают кнопку «Войти через Google», запускается поток авторизации через Google и он переводит пользователей на сайт Google. Оказавшись там, они входят в систему со своими учетными данными Google, после чего они будут перенаправлены на страницу подтверждения.

На странице подтверждения у пользователей будет запрошено разрешение на передачу информации о своей учетной записи Google на сторонний сайт. В этом случае сторонний сайт — это сайт, на котором они хотят использовать свою учетную запись Google для входа в систему. Им будут представлены два варианта: они могут разрешить или запретить это.

После того, как они разрешат поделиться своей информацией со сторонним сайтом, пользователи будут перенаправлены на сторонний сайт, откуда они инициировали поток входа в Google.

На этом этапе пользователь вошел в систему с помощью Google, а сторонний сайт имеет доступ к информации профиля пользователя, которую можно использовать для создания учетной записи и входа в систему.

Это основной процесс интеграции авторизации Google на вашем сайте. В оставшейся части поста мы реализуем этот поток входа в рабочем примере на PHP.

Настройка проекта для авторизации через Google

В этом разделе мы рассмотрим основные настройки, необходимые для интеграции авторизации через Google с вашим веб-сайтом на PHP.

Создайте проект Google API

Во-первых, вам нужно создать приложение в Google, которое позволит вам зарегистрировать свой сайт в Google. Это позволяет вам настроить основную информацию о вашем сайте, а также пару технических деталей.

После того, как вы вошли в систему с помощью Google, откройте консоль разработчиков Google. Откроется страница панели инструментов Google, как показано на следующем снимке экрана.

В верхнем левом меню нажмите на ссылку «Выбрать проект». Откроется всплывающее окно, как показано на снимке экрана.

Нажмите на ссылку «Новый проект», в появившейся панели вам нужно будет ввести название проекта и другую информацию. Заполните необходимые данные, как показано в следующем снимке экрана.

Нажмите кнопку «Создать», чтобы сохранить новый проект. Вы будете перенаправлены на страницу панели инструментов. Нажмите «Учетные данные» в левой боковой панели и перейдите на вкладку настроек OAuth.

На этой странице вам нужно ввести информацию о приложении, такую как название приложения, логотип и некоторые другие данные. Заполните необходимые данные и сохраните их. Для целей тестирования достаточно просто ввести имя приложения.

Затем нажмите «Учетные данные» в левой боковой панели. Должно отобразиться поле «Учетные данные API», как показано на следующем снимке экрана.

Нажмите «Учетные данные клиента»> «Идентификатор клиента OAuth», чтобы создать новый набор учетных данных для приложения. Отобразится панель, в которой вам будет предложено выбрать нужный вариант. В нашем случае выберите опцию «Веб-приложение» и нажмите кнопку «Создать». Вам будет предложено предоставить несколько более подробную информацию.

Введите данные, показанные на снимке экрана выше, и сохраните их! Конечно, вам нужно установить URI перенаправления в соответствии с настройками вашего приложения. Это URL, по которому пользователь будет перенаправлен после входа в систему.

На данный момент мы создали клиентское приложение Google OAuth2, и теперь нам нужно получить возможность использовать это приложение для интеграции на нашем сайте входа в систему через Google. Пожалуйста, запишите идентификатор клиента и секретный ключ клиента, они потребуются при настройке приложения с нашей стороны. Вы всегда можете найти идентификатор клиента и секретный ключ клиента при редактировании приложения.

Установите клиентскую библиотеку Google PHP SDK

В этом разделе мы рассмотрим, как установить клиентскую библиотеку Google PHP API. Есть два варианта установки:

Загрузить и установить файлы библиотеки вручную.

Бесплатный курс по PHP программированию

Освойте курс и узнайте, как создать динамичный сайт на PHP и MySQL с полного нуля, используя модель MVC

В курсе 39 уроков | 15 часов видео | исходники для каждого урока

Использовать Composer

Если вы предпочитаете установить его с помощью Composer, вам просто нужно выполнить следующую команду.

Getting Google OAuth Access Token using Google APIs

If you need to access your Google drive and read your contents through an API, you will need the Google OAuth access token associated with your google drive.

Here I have explained how to get that access token using Google APIs.

  1. Go to this link.
  2. Login to your Google account.
  3. Create a project using a project name and click on “CREATE” button.

4. Select the project you have created.

5. Click on “Open” button.

6. To enable Google Drive API, click on Google Drive API and then click on “ENABLE” button.

7. Click on Create Credentials button.

8. Choose Web browser (Javascript)” for the “Where will you be calling the API from?” dropdown.

9. Select “ User data” for the “What data will you be accessing?”.

10. Click on “What credentials do I need?” button.

11. Provide a redirect URL for the “Authorized redirect URIs”.
Ex:
https://www.maxsoftlk.com

12. Click on “Create OAuth client ID” button.

13. Provide a product name”.
Ex: Test1

14. Click on “Continue” button.

15. Click on “Download” button to download this credential information in JSON format.

16. Click on “Done” button.

17. Change this URL according to the parameters given by you in the above steps.

Note: Your Client ID can be found from the file you have downloaded in step 15.

18. Copy the above URL and paste it in an incognito mode of your browser.

19. Select the Google account which you have logged in previously.

20. If you are come-up with this screen, click on Advanced link and then click on go with unsafe mode link.

Using OAuth 2.0 to Access Google APIs

Google APIs use the OAuth 2.0 protocol for authentication and authorization. Google supports common OAuth 2.0 scenarios such as those for web server, client-side, installed, and limited-input device applications.

To begin, obtain OAuth 2.0 client credentials from the Google API Console. Then your client application requests an access token from the Google Authorization Server, extracts a token from the response, and sends the token to the Google API that you want to access. For an interactive demonstration of using OAuth 2.0 with Google (including the option to use your own client credentials), experiment with the OAuth 2.0 Playground.

This page gives an overview of the OAuth 2.0 authorization scenarios that Google supports, and provides links to more detailed content. For details about using OAuth 2.0 for authentication, see OpenID Connect.

Basic steps

All applications follow a basic pattern when accessing a Google API using OAuth 2.0. At a high level, you follow five steps:

1. Obtain OAuth 2.0 credentials from the Google API Console.

Visit the Google API Console to obtain OAuth 2.0 credentials such as a client ID and client secret that are known to both Google and your application. The set of values varies based on what type of application you are building. For example, a JavaScript application does not require a secret, but a web server application does.

Читать еще:  Allow access перевод

2. Obtain an access token from the Google Authorization Server.

Before your application can access private data using a Google API, it must obtain an access token that grants access to that API. A single access token can grant varying degrees of access to multiple APIs. A variable parameter called scope controls the set of resources and operations that an access token permits. During the access-token request, your application sends one or more values in the scope parameter.

There are several ways to make this request, and they vary based on the type of application you are building. For example, a JavaScript application might request an access token using a browser redirect to Google, while an application installed on a device that has no browser uses web service requests.

Some requests require an authentication step where the user logs in with their Google account. After logging in, the user is asked whether they are willing to grant one or more permissions that your application is requesting. This process is called user consent .

If the user grants at least one permission, the Google Authorization Server sends your application an access token (or an authorization code that your application can use to obtain an access token) and a list of scopes of access granted by that token. If the user does not grant the permission, the server returns an error.

It is generally a best practice to request scopes incrementally, at the time access is required, rather than up front. For example, an app that wants to support saving an event to a calendar should not request Google Calendar access until the user presses the «Add to Calendar» button; see Incremental authorization.

3. Examine scopes of access granted by the user.

Compare the scopes included in the access token response to the scopes required to access features and functionality of your application dependent upon access to a related Google API. Disable any features of your app unable to function without access to the related API.

The scope included in your request may not match the scope included in your response, even if the user granted all requested scopes. Refer to the documentation for each Google API for the scopes required for access. An API may map multiple scope string values to a single scope of access, returning the same scope string for all values allowed in the request. Example: the Google People API may return a scope of https://www.googleapis.com/auth/contacts when an app requested a user authorize a scope of https://www.google.com/m8/feeds/ ; the Google People API method people.updateContact requires a granted scope of https://www.googleapis.com/auth/contacts .

4. Send the access token to an API.

After an application obtains an access token, it sends the token to a Google API in an HTTP Authorization request header. It is possible to send tokens as URI query-string parameters, but we don’t recommend it, because URI parameters can end up in log files that are not completely secure. Also, it is good REST practice to avoid creating unnecessary URI parameter names.

Access tokens are valid only for the set of operations and resources described in the scope of the token request. For example, if an access token is issued for the Google Calendar API, it does not grant access to the Google Contacts API. You can, however, send that access token to the Google Calendar API multiple times for similar operations.

5. Refresh the access token, if necessary.

Access tokens have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.

Scenarios

Web server applications

The Google OAuth 2.0 endpoint supports web server applications that use languages and frameworks such as PHP, Java, Python, Ruby, and ASP.NET.

The authorization sequence begins when your application redirects a browser to a Google URL; the URL includes query parameters that indicate the type of access being requested. Google handles the user authentication, session selection, and user consent. The result is an authorization code, which the application can exchange for an access token and a refresh token.

The application should store the refresh token for future use and use the access token to access a Google API. Once the access token expires, the application uses the refresh token to obtain a new one.

Installed applications

The Google OAuth 2.0 endpoint supports applications that are installed on devices such as computers, mobile devices, and tablets. When you create a client ID through the Google API Console, specify that this is an Installed application, then select Android, Chrome App, iOS, or «Other» as the application type.

The process results in a client ID and, in some cases, a client secret, which you embed in the source code of your application. (In this context, the client secret is obviously not treated as a secret.)

The authorization sequence begins when your application redirects a browser to a Google URL; the URL includes query parameters that indicate the type of access being requested. Google handles the user authentication, session selection, and user consent. The result is an authorization code, which the application can exchange for an access token and a refresh token.

The application should store the refresh token for future use and use the access token to access a Google API. Once the access token expires, the application uses the refresh token to obtain a new one.

Client-side (JavaScript) applications

The Google OAuth 2.0 endpoint supports JavaScript applications that run in a browser.

The authorization sequence begins when your application redirects a browser to a Google URL; the URL includes query parameters that indicate the type of access being requested. Google handles the user authentication, session selection, and user consent.

The result is an access token, which the client should validate before including it in a Google API request. When the token expires, the application repeats the process.

Applications on limited-input devices

The Google OAuth 2.0 endpoint supports applications that run on limited-input devices such as game consoles, video cameras, and printers.

The authorization sequence begins with the application making a web service request to a Google URL for an authorization code. The response contains several parameters, including a URL and a code that the application shows to the user.

The user obtains the URL and code from the device, then switches to a separate device or computer with richer input capabilities. The user launches a browser, navigates to the specified URL, logs in, and enters the code.

Читать еще:  Header set access control allow origin

Meanwhile, the application polls a Google URL at a specified interval. After the user approves access, the response from the Google server contains an access token and refresh token. The application should store the refresh token for future use and use the access token to access a Google API. Once the access token expires, the application uses the refresh token to obtain a new one.

Service accounts

Google APIs such as the Prediction API and Google Cloud Storage can act on behalf of your application without accessing user information. In these situations your application needs to prove its own identity to the API, but no user consent is necessary. Similarly, in enterprise scenarios, your application can request delegated access to some resources.

For these types of server-to-server interactions you need a service account, which is an account that belongs to your application instead of to an individual end-user. Your application calls Google APIs on behalf of the service account, and user consent is not required. (In non-service-account scenarios, your application calls Google APIs on behalf of end-users, and user consent is sometimes required.)

A service account’s credentials, which you obtain from the Google API Console, include a generated email address that is unique, a client ID, and at least one public/private key pair. You use the client ID and one private key to create a signed JWT and construct an access-token request in the appropriate format. Your application then sends the token request to the Google OAuth 2.0 Authorization Server, which returns an access token. The application uses the token to access a Google API. When the token expires, the application repeats the process.

Token size

Tokens can vary in size, up to the following limits:

  • Authorization codes: 256 bytes
  • Access tokens: 2048 bytes
  • Refresh tokens: 512 bytes

Google reserves the right to change token size within these limits, and your application must support variable token sizes accordingly.

Refresh token expiration

You must write your code to anticipate the possibility that a granted refresh token might no longer work. A refresh token might stop working for one of these reasons:

  • The user has revoked your app’s access.
  • The refresh token has not been used for six months.
  • The user changed passwords and the refresh token contains Gmail scopes.
  • The user account has exceeded a maximum number of granted (live) refresh tokens.

There is currently a limit of 50 refresh tokens per user account per client. If the limit is reached, creating a new refresh token automatically invalidates the oldest refresh token without warning. This limit does not apply to service accounts.

There is also a larger limit on the total number of refresh tokens a user account or service account can have across all clients. Most normal users won’t exceed this limit but a developer’s test account might.

If you need to authorize multiple programs, machines, or devices, one workaround is to limit the number of clients that you authorize per user account to 15 or 20. If you are a G Suite admin, you can create additional admin users and use them to authorize some of the clients.

Client libraries

The following client libraries integrate with popular frameworks, which makes implementing OAuth 2.0 simpler. More features will be added to the libraries over time.

Except as otherwise noted, the content of this page is licensed under the Creative Commons Attribution 4.0 License, and code samples are licensed under the Apache 2.0 License. For details, see the Google Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Авторизация с помощью Google Sign In

Задача урока: успешная авторизация пользователя через google аккаунт.

Условия выполнения: отображение информации из профиля + токен юзера.

Видео-версия

Подготовка

Для авторизации потребуется «приложение» google и проект на localhost (create-react-app подходит без проблем).

Создайте новый проект:

После создания ваш проект будет выбран автоматически (если он единственный). Пройдите в раздел Credentials.

Далее нужно создать OAuth client ID, выбрать тип приложения Web Application и добавить разрешенный домен, с которого вы будете выполнять запросы. Инструкция в картинках ниже.

В конечном счете, у вас будет ключ (client ID):

Разработка

  • развернуть create-react-app (в статье не обсуждается);
  • добавить скрипт google api;
  • разобраться с документацией;
  • залогинить пользователя.

После успешного запуска create-react-app второй версии, в браузере можно увидеть следующее:

Создайте в корне файл .env , в котором будет храниться ваш CLIENT_ID ключ, добавьте этот файл в .gitignore, если планируете использовать git.

Все, что начинается с REACT_APP_ в cra будет доступно через process.env , например: process.env.REACT_APP_GOOGLE_CLIENT_ID вернет ваш ключ из «секретного» файла. Подробнее в статье (англ).

Добавьте на главную страницу в head скрипт от google.

Теперь взглянем в документацию, в раздел Home (не торопитесь добавлять все, что выделено)

Как видите, помимо скрипта в примере присутствуют и другие «инструкции» для корректной работы. Но проблема в том, что такое поведение не подойдет для react-приложения. Поэтому, мы добавляем только скрипт, а все остальное будем делать с помощью методов API, которые описаны на вкладке Reference.

Документацию желательно, если не прочитать, то хотя бы неспешно прокрутить и прочесть заголовки, так как, вы должны ориентироваться в первоисточнике.

Добавляем авторизацию через google в сreate-react-app

Остался последний пункт плана — «залогинить пользователя». Для этого, разобьем его на шаги:

  • инициализировать модуль gapi.auth2 ;
  • добавить функцию-обработчик на логин и на логаут;
  • вывести информацию о пользователе после успешного логина в консоль;
  • [бонус] оформить информацию на странице приложения, добавить красоты.

Для выполнения пунктов, нам понадобятся следующие методы:

  • gapi.auth2.init(params) — для инициализации (будем использовать в componentDidMount). Понадобится ваш ключ (client ID)
  • gapi.auth2.getAuthInstance() — чтобы получить объект GoogleAuth , который умеет:
    • GoogleAuth.signIn() — проивзодить логин
    • GoogleAuth.signOut() — производить логаут

Все методы взяты из документации, где вы можете ознакомиться и с другими полезными функциями.

Удалим лишнее из компонента и добавим необходимое:

(внимание, крутящееся лого реакта может перекрывать ваши элементы, и они будут не кликабельны)

Проверим, что в консоли:

По клику на Log in появится всплывающее окно

После выбора профиля — в консоль «упадет» информация из профиля

Комментарии по коду для «совсем новичков»: после добавления скрипта от google, у нас появился глобальный объект gapi , который лучше вызывать как window.gapi , чтобы программист, который читает ваш код не искал где объявлена переменная gapi .

Далее в cdm и в обработчиках signIn / signOut используется стандартный подход, когда в promise возвращается либо информация об объекте в случае успеха, либо ошибка.

Воспользуемся state и «подкрутим» пример:

Итоги

Мы научились использовать механизм входа «через google». В данный момент у нас есть возможность вытащить token, с помощью которого можно выполнять запросы к Google API. Также токен можно передавать на свой бэкэнд и там его «расшифровать». Это рекомендуемый способ, так как передавать ID пользователя или прочую информацию — небезопасно.

Ссылка на основную публикацию
ВсеИнструменты 220 Вольт
Adblock
detector