АдминистрированиеЛицензия.СетевойКлюч

Свойства · NetworkKey

Тип: Булево. Указывает статус использования аппаратного ключа защиты: Истина, если для аппаратной лицензии ключ защиты программы является сетевым, лицензия получена через менеджер лицензий Aladdin License Manager; Ложь в противном случае.

Полное описание, параметры и ограничения

АдминистрированиеЛицензия.СетевойКлюч (AdministrationLicense.NetworkKey)

АдминистрированиеЛицензия (AdministrationLicense)

СетевойКлюч (NetworkKey)

Доступен, начиная с версии 8.3.14.

Использование:
Только чтение.
Описание:
Тип: Булево.
Указывает статус использования аппаратного ключа защиты:
Истина, если для аппаратной лицензии ключ защиты программы является сетевым, лицензия получена через менеджер лицензий Aladdin License Manager;

Ложь в противном случае.

Доступность:

Тонкий клиент, сервер, толстый клиент, интеграция.

Использование в версии:

Доступен, начиная с версии 8.3.14.

Методическая информация

Практические примеры

Своя административная лицензия: настоящий источник, классификация и два приватных чтения

Цельный собственный RAS-процесс выбирает реальный клиентский сеанс из отдельно подготовленной VM, получает native массив лицензий, классифицирует поля и сравнивает два чтения. Никаких фиктивных UUID/лицензий, установки или доказательства юридической действительности. Изготовлены лишь исходники и статические тесты.

Где и как запускать

Полный модуль обычной формы отдельной файловой CF УчебныеЛицензии85Пульт, только толстый ordinary клиент own VM OWN-LIC85/8.5.1.1343. Actual source — собственный заранее подготовленный RAS и один конкретный target сеанс. Supporting module — отдельно управляемая target форма, client/server declarations точны.

Подготовка

  1. Не выполняйте в рабочей системе. Нужна собственная изолированная Windows VM с сетевым именем OWN-LIC85 и уже подготовленной владельцем разрешённой для этого стенда лицензией. Не клонируйте рабочую VM, не копируйте .lic/PIN и не активируйте/покупайте лицензию ради упражнения. Если законно подготовленного стенда ещё нет, этот урок пока не выполняется; код его не создаёт и не доказывает владение.

  2. Вручную собственный администратор готовит только отдельный сервер/RAS8.5.1.1343 в этой VM: агент15440, менеджер собственного кластера15441, свой диапазон рабочих процессов15600–15610, RAS слушает127.0.0.1:18585 и связан только с данным own агентом. Ни production, ни чужие RAS не подключаются. Один кластер Имя=УчебныеЛицензии85_0f605d14. Existing агентный администратор OwnLicenseAgent85 и отдельный existing кластерный OwnLicenseCluster85 имеют известные только владельцу непустые пароли; подготовьте их вручную до урока, не сохраняйте пароли в исходнике.

  3. В этом выделенном кластере вручную зарегистрируйте одну совершенно новую пустую server-ИБ с регистрационным именем УчебныйКлиентЛицензий85_0f605d14, своей отдельной новой пустой БД и собственной CF УчебныеЛицензии85Клиент. Основной режим управляемый. Никаких каталогов, документов, регистров, extensions, заданий и рабочих modules; лишь обработка УчебныйКлиент85 с основной управляемой формой. Реквизит Состояние85 Строка неограниченная, поле только просмотр. Supporting module ниже вставьте целиком в эту форму, ПриОткрытии(Отказ) назначьте native событию.

  4. В own target-ИБ вручную подготовьте пользователя Лицензии85Клиент с разрешением открыть только свой учебный интерфейс. Запустите на OWN-LIC85 ровно один толстый управляемый клиент данной ИБ с connection Srvr="127.0.0.1:15441";Ref="УчебныйКлиентЛицензий85_0f605d14";, без других частей connection. Loopback предотвращает зависимость от LAN DNS/IP. Собственная форма выполнит чтение серверного номера и останется открытой. Не держите Конфигуратор/второй клиент/фоновые сеансы target-ИБ во время RAS чтений. Не меняйте выдачу лицензий, key manager или режимы получения.

  5. В той же VM вручную создайте новую пустую файловую CF УчебныеЛицензии85Пульт только по C:\1C85_OwnLicenseLab\0f605d14-979e-4970-b5fb-32f18510a40b\Pult. Если точная папка уже занята, не удаляйте/не используйте чужие данные: подготовьте новый собственный стенд и согласованно измените все guards. Основной режим обычный, только одна обработка ПультЛицензий85 с обычной основной формой; бизнес-объектов/расширений/заданий нет. Пульт запускается толстым обычным клиентом, не создавая второй кластерный сеанс.

  6. Форма пульта: UUIDКластера85, UUIDБазы85, UUIDСеанса85, PIDКлиента85 Строка; НомерСеанса85 Число(10,0); ПарольАгента85 и ПарольКластера85 Строка с полями РежимПароля=Да; Отчет85 и Состояние85 Строка неограниченная, большие многострочные поля только просмотра. Не сохраняйте реквизиты/пароли в настройках формы. Main code целиком в модуле ordinary формы; назначьте ПриОткрытии() и ПриЗакрытии() одноимённым событиям. Кнопки ПрочитатьПервыйСнимок85 и СравнитьВтороеЧтение85 — одноимённые native действия с параметром Кнопка.

  7. Откройте только собственную консоль кластера этой VM и вручную скопируйте actual UUID собственного кластера, actual UUID единственной target-ИБ и actual UUID её одного сеанса Лицензии85Клиент в поля пульта. Не подставляйте marker из названия папки вместо actual UUID! НомерСеанса85 возьмите из поддерживающей target-формы и сверяйте с тем же сеансом консоли. В Диспетчере задач собственной VM → Подробности сопоставьте именно её target 1cv8.exe (не пульт/ras/rphost) и скопируйте настоящий OS PID в PIDКлиента85. Номер сеанса, UUID и PID — три разные сущности.

  8. Проверьте глазами соответствие VM/кластера/ИБ/сеанса и заранее разрешённую владельцем лицензию. Введите только свои два пароля непосредственно перед первым чтением. Код аутентифицирует native агент в порядке (Пароль, Имя), native кластер в порядке (Имя, Пароль); все имена/endpoint фиксированы на own стенд. После успеха или отказа поля паролей очищаются, повторное чтение требует нового локального ввода.

#Если ТолстыйКлиентОбычноеПриложение Тогда

Перем ПервыйСнимок85;

Процедура ПриОткрытии()
    ПроверитьСвойПустойСтенд();
    ПроверитьСвоюVMИПуть85();
    ПервыйСнимок85 = Неопределено;
    СброситьСвоиПароли85();
    Отчет85 = "";
    Состояние85 = "Введите actual UUID только своего кластера/ИБ/сеанса и OS PID своего клиента. Лицензия уже подготовлена владельцем стенда; этот урок её не устанавливает.";
КонецПроцедуры

Процедура ПриЗакрытии()
    СброситьСвоиПароли85();
    ПервыйСнимок85 = Неопределено;
КонецПроцедуры

Процедура ПрочитатьПервыйСнимок85(Кнопка)
    Попытка
        Снимок = ПрочитатьСвоиЛицензии85();
    Исключение
        СброситьСвоиПароли85();
        Состояние85 = "Чтение прервано. Проверьте собственные UUID, номер/PID клиента, имена/порты, версию и доступ. Ранее показанный результат не заменён. Текст native ошибки не печатаем: он может содержать приватные сведения.";
        ВызватьИсключение "Свой первый снимок не получен; это не заключение о действительности лицензии";
    КонецПопытки;
    СброситьСвоиПароли85();
    ПервыйСнимок85 = Снимок;
    Отчет85 = Снимок.Отчет;
    Состояние85 = "Первое чтение сохранено только в памяти этой формы. Для сравнения снова введите свои два пароля и нажмите СравнитьВтороеЧтение85.";
КонецПроцедуры

Процедура СравнитьВтороеЧтение85(Кнопка)
    Попытка
        Если ПервыйСнимок85 = Неопределено Тогда
            ВызватьИсключение "Сначала нужно первое actual чтение";
        КонецЕсли;
        ПроверитьСвоиВведенныеИдентификаторы85();
        Если НРег(СокрЛП(UUIDКластера85)) <> НРег(Строка(ПервыйСнимок85.КластерUUID))
            Или НРег(СокрЛП(UUIDБазы85)) <> НРег(Строка(ПервыйСнимок85.БазаUUID))
            Или НРег(СокрЛП(UUIDСеанса85)) <> НРег(Строка(ПервыйСнимок85.СеансUUID)) Тогда
            ВызватьИсключение "Второй снимок допускается только для прежних actual UUID";
        КонецЕсли;
        Второй = ПрочитатьСвоиЛицензии85();
        Если Второй.КластерUUID <> ПервыйСнимок85.КластерUUID Или Второй.БазаUUID <> ПервыйСнимок85.БазаUUID
            Или Второй.СеансUUID <> ПервыйСнимок85.СеансUUID Тогда
            ВызватьИсключение "Actual источник двух чтений различается";
        КонецЕсли;
    Исключение
        СброситьСвоиПароли85();
        Состояние85 = "Второе чтение не принято. Первый результат сохранён. Новый/исчезнувший сеанс нельзя подменить первым элементом списка; обновите own идентичность отдельным первым чтением.";
        ВызватьИсключение "Свои два чтения не сопоставлены; приватные native подробности не выводятся";
    КонецПопытки;
    СброситьСвоиПароли85();
    Совпало = ПервыйСнимок85.ЗакрытыйОтпечаток = Второй.ЗакрытыйОтпечаток;
    Отчет85 = ПервыйСнимок85.Отчет + Символы.ПС + Символы.ПС + "Второе чтение:" + Символы.ПС + Второй.Отчет;
    Состояние85 = ?(Совпало, "Считанные наборы значений совпали", "Считанные наборы значений различаются")
        + ". Сравнение касается только двух чтений одного actual сеанса. Это НЕ проверка юридических прав, подписи, действительности лицензии или атомарности диагностики. Закрытые отпечатки не показаны.";
КонецПроцедуры

Процедура СброситьСвоиПароли85()
    ПарольАгента85 = "";
    ПарольКластера85 = "";
КонецПроцедуры

Процедура ПроверитьСвоюVMИПуть85()
    Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Тогда
        ВызватьИсключение "Только вручную подготовленная собственная VM OWN-LIC85";
    КонецЕсли;
    Части = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
    Если Части.Количество() <> 1 И Части.Количество() <> 2 Тогда
        ВызватьИсключение "Пульт должен быть своей файловой базой с единственным File";
    КонецЕсли;
    Если Части.Количество() = 2 И СокрЛП(Части[1]) <> "" Тогда
        ВызватьИсключение "Параметры после File для собственного пульта не разрешены";
    КонецЕсли;
    Параметр = СокрЛП(Части[0]);
    Если НРег(Лев(Параметр, 5)) <> "file=" Тогда
        ВызватьИсключение "Пульт нельзя запускать из рабочего серверного подключения";
    КонецЕсли;
    Путь = Сред(Параметр, 6);
    Если Лев(Путь, 1) = """" И Прав(Путь, 1) = """" Тогда
        Путь = Сред(Путь, 2, СтрДлина(Путь) - 2);
    КонецЕсли;
    Если НРег(Путь) <> НРег("C:\1C85_OwnLicenseLab\0f605d14-979e-4970-b5fb-32f18510a40b\Pult") Тогда
        ВызватьИсключение "Нужен exact собственный UUID-путь Pult без относительных путей или завершающего слеша";
    КонецЕсли;
КонецПроцедуры

Процедура ПроверитьСвоиВведенныеИдентификаторы85()
    Если UUIDКластера85 = "" Или UUIDБазы85 = "" Или UUIDСеанса85 = "" Или НомерСеанса85 <= 0 Тогда
        ВызватьИсключение "Сначала скопируйте actual три UUID и номер своего сеанса из собственной консоли";
    КонецЕсли;
    Если СтрДлина(PIDКлиента85) = 0 Или СтрДлина(PIDКлиента85) > 10 Тогда
        ВызватьИсключение "Нужен OS PID собственного target-клиента, не UUID и не номер сеанса";
    КонецЕсли;
    Для НомерСимвола = 1 По СтрДлина(PIDКлиента85) Цикл
        Если СтрНайти("0123456789", Сред(PIDКлиента85, НомерСимвола, 1)) = 0 Тогда
            ВызватьИсключение "PID собственного процесса должен содержать только цифры";
        КонецЕсли;
    КонецЦикла;
    Если Число(PIDКлиента85) <= 0 Или Формат(Число(PIDКлиента85), "ЧГ=0;ЧДЦ=0") <> PIDКлиента85 Тогда
        ВызватьИсключение "Нужен положительный канонический OS PID из своей VM";
    КонецЕсли;
КонецПроцедуры

Функция СвойЛокальныйАдрес85(Адрес)
    Возврат НРег(Адрес) = "own-lic85" Или Адрес = "127.0.0.1" Или Адрес = "::1";
КонецФункции

Функция НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID)
    Сеансы = Кластер.ПолучитьСеансы();
    Если ТипЗнч(Сеансы) <> Тип("Массив") Или Сеансы.Количество() <> 1 Тогда
        ВызватьИсключение "В выделенном своём кластере разрешён только один собственный target-сеанс";
    КонецЕсли;
    Сеанс = Сеансы[0];
    Если ТипЗнч(Сеанс) <> Тип("АдминистрированиеСеанс") Тогда
        ВызватьИсключение "Источник должен быть настоящим native административным сеансом";
    КонецЕсли;
    Если Сеанс.ИдентификаторИнформационнойБазы <> БазаUUID Или Сеанс.ИдентификаторСеанса <> СеансUUID
        Или Сеанс.НомерСеанса <> НомерСеанса85 Или Сеанс.ИмяПользователя <> "Лицензии85Клиент"
        Или Не СвойЛокальныйАдрес85(Сеанс.ИмяКомпьютера) Или Не СвойЛокальныйАдрес85(Сеанс.IPАдресКлиента)
        Или Сеанс.ИмяПриложения <> "1CV8" Тогда
        ВызватьИсключение "Actual сеанс не совпал со своей ИБ/UUID/номером/user/VM/толстым target-клиентом";
    КонецЕсли;
    Возврат Сеанс;
КонецФункции

Функция ПрочитатьСвоиЛицензии85()
    ПроверитьСвойПустойСтенд();
    ПроверитьСвоюVMИПуть85();
    ПроверитьСвоиВведенныеИдентификаторы85();
    Если ПарольАгента85 = "" Или ПарольКластера85 = "" Тогда
        ВызватьИсключение "Два существующих собственных администратора требуют непустые пароли; пустую auth не пробуем";
    КонецЕсли;
    КластерUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDКластера85));
    БазаUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDБазы85));
    СеансUUID = Новый УникальныйИдентификатор(СокрЛП(UUIDСеанса85));
    Начало = ТекущаяДата();
    Агент = Новый АдминистрированиеСервера("127.0.0.1", 18585);
    Если Агент.ПолучитьВерсию() <> "8.5.1.1343" Тогда
        ВызватьИсключение "Own RAS endpoint должен относиться к серверу8.5.1.1343";
    КонецЕсли;
    Агент.ВыполнитьАутентификацию(ПарольАгента85, "OwnLicenseAgent85");
    Кластеры = Агент.ПолучитьКластеры();
    Если ТипЗнч(Кластеры) <> Тип("Массив") Или Кластеры.Количество() <> 1 Тогда
        ВызватьИсключение "Отдельный endpoint обязан иметь только один свой кластер";
    КонецЕсли;
    Кластер = Кластеры[0];
    Если ТипЗнч(Кластер) <> Тип("АдминистрированиеКластер") Или Кластер.ИдентификаторКластера <> КластерUUID
        Или Кластер.Имя <> "УчебныеЛицензии85_0f605d14" Или Кластер.Порт <> 15441
        Или Не СвойЛокальныйАдрес85(Кластер.ИмяКомпьютера) Тогда
        ВызватьИсключение "Actual кластер не совпал с exact own UUID/name/host/port";
    КонецЕсли;
    Кластер.ВыполнитьАутентификацию("OwnLicenseCluster85", ПарольКластера85);
    Базы = Кластер.ПолучитьИнформационныеБазы();
    Если ТипЗнч(Базы) <> Тип("Массив") Или Базы.Количество() <> 1 Тогда
        ВызватьИсключение "В выделенном кластере должна быть только одна своя новая пустая target-ИБ";
    КонецЕсли;
    База = Базы[0];
    Если ТипЗнч(База) <> Тип("АдминистрированиеИнформационнаяБаза") Или База.ИдентификаторИнформационнойБазы <> БазаUUID
        Или База.Имя <> "УчебныйКлиентЛицензий85_0f605d14" Тогда
        ВызватьИсключение "Actual target-ИБ не совпала со своим UUID и регистрационным именем";
    КонецЕсли;
    Сеанс = НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID);
    Процессы = Кластер.ПолучитьРабочиеПроцессы();
    Если ТипЗнч(Процессы) <> Тип("Массив") Тогда
        ВызватьИсключение "Native список рабочих процессов должен быть массивом";
    КонецЕсли;
    СвойПроцесс = Неопределено;
    Для Каждого Процесс Из Процессы Цикл
        Если ТипЗнч(Процесс) <> Тип("АдминистрированиеРабочийПроцесс") Или Не СвойЛокальныйАдрес85(Процесс.ИмяКомпьютера) Тогда
            ВызватьИсключение "Рабочие процессы должны принадлежать только собственной VM";
        КонецЕсли;
        Если Процесс.ИдентификаторРабочегоПроцесса = Сеанс.ИдентификаторПроцесса Тогда
            Если СвойПроцесс <> Неопределено Тогда
                ВызватьИсключение "Actual UUID рабочего процесса оказался неоднозначным";
            КонецЕсли;
            СвойПроцесс = Процесс;
        КонецЕсли;
    КонецЦикла;
    Если СвойПроцесс = Неопределено Или Не СвойПроцесс.Активен Тогда
        ВызватьИсключение "Связанный actual рабочий процесс уже не найден/не активен";
    КонецЕсли;
    Лицензии = Сеанс.Лицензии;
    Если ТипЗнч(Лицензии) <> Тип("Массив") Тогда
        ВызватьИсключение "Native Лицензии своего сеанса должны быть массивом";
    КонецЕсли;
    Строки = Новый Массив;
    Строки.Добавить("Client-license чтение: " + Формат(Начало, "ДФ=yyyy-MM-dd HH:mm:ss"));
    Строки.Добавить("Actual UUID сеанса: " + Строка(Сеанс.ИдентификаторСеанса));
    Строки.Добавить("Элементов административных сведений: " + Строка(Лицензии.Количество()) + ". Это НЕ число свободных лицензий.");
    Отпечатки = Новый ТаблицаЗначений;
    Отпечатки.Колонки.Добавить("Отпечаток", Новый ОписаниеТипов("Строка"));
    Номер = 0;
    Для Каждого Лицензия Из Лицензии Цикл
        Если ТипЗнч(Лицензия) <> Тип("АдминистрированиеЛицензия") Тогда
            ВызватьИсключение "Реальный элемент native Лицензии имеет другой тип; подмену/искусственный ctor не используем";
        КонецЕсли;
        Адрес = Лицензия.АдресСервера;
        PID = Лицензия.ИдентификаторПроцесса;
        ФайлЛицензии = Лицензия.ИмяФайла;
        Краткое = Лицензия.КраткоеПредставление;
        Максимум = Лицензия.МаксимальноеКоличествоПользователей;
        МаксимумКомплекта = Лицензия.МаксимальноеКоличествоПользователейПрограммнойЛицензии;
        Подробное = Лицензия.ПодробноеПредставление;
        ОтСервера = Лицензия.ПолученаСервером;
        Порт = Лицензия.ПортСервера;
        Программная = Лицензия.ПрограммнаяЛицензия;
        Серия = Лицензия.СерияКлюча;
        Сетевая = Лицензия.СетевойКлюч;
        Для Каждого Текст Из Новый Структура("Адрес,PID,Файл,Краткое,Подробное,Серия", Адрес, PID, ФайлЛицензии, Краткое, Подробное, Серия) Цикл
            Если ТипЗнч(Текст.Значение) <> Тип("Строка") Или СтрДлина(Текст.Значение) > 1000000 Тогда
                ВызватьИсключение "Неожиданный тип/размер native строк; приватные значения не выводятся";
            КонецЕсли;
        КонецЦикла;
        Если ТипЗнч(Максимум) <> Тип("Число") Или ТипЗнч(МаксимумКомплекта) <> Тип("Число") Или ТипЗнч(Порт) <> Тип("Число")
            Или ТипЗнч(ОтСервера) <> Тип("Булево") Или ТипЗнч(Программная) <> Тип("Булево") Или ТипЗнч(Сетевая) <> Тип("Булево") Тогда
            ВызватьИсключение "Native numeric/bool поля не совпали с документированными типами";
        КонецЕсли;
        Номер = Номер + 1;
        Вид = ?(Программная, "программная", ?(Сетевая, "аппаратная, сетевой ключ через Aladdin License Manager", "аппаратная, без признака сетевого ключа"));
        Источник = ?(ОтСервера, "получена сервером 1С и выдана клиенту", "получена клиентским приложением");
        Сопоставление = "PID не сопоставлен с выбранным собственным процессом; это не признак недействительности";
        Если ОтСервера Тогда
            Если PID = СвойПроцесс.ИдентификаторПроцесса И СвойЛокальныйАдрес85(Адрес) Тогда
                Сопоставление = "PID/host совпали с OS PID связанного own рабочего процесса; UUID процесса для этого не использовался";
            КонецЕсли;
        ИначеЕсли PID = PIDКлиента85 И СвойЛокальныйАдрес85(Адрес) Тогда
            Сопоставление = "PID/host совпали с вручную подтверждённым собственным клиентским OS PID";
        КонецЕсли;
        Предупреждения = Новый Массив;
        Если Не Программная И МаксимумКомплекта <> Максимум Тогда
            Предупреждения.Добавить("Для аппаратной лицензии справка описывает равные MaxUsers/MaxSoftwareLicenseUsers; здесь они различаются. Повторите собственное чтение, не объявляйте юридический результат.");
        КонецЕсли;
        Если Программная И Сетевая Тогда
            Предупреждения.Добавить("NetworkKey относится к аппаратному ключу; SoftwareLicense/NetworkKey требуют отдельного наблюдения, не локализованного string parsing.");
        КонецЕсли;
        Если Максимум < 0 Или МаксимумКомплекта < 0 Или Порт < 0 Или Порт > 65535 Тогда
            Предупреждения.Добавить("Численные поля неожиданны для этого стенда; это только диагностическое предупреждение.");
        КонецЕсли;
        Строки.Добавить("Элемент " + Строка(Номер) + ": " + Вид + "; " + Источник);
        Строки.Добавить("Предел используемого ключа/файла=" + Строка(Максимум)
            + "; предел программного комплекта=" + Строка(МаксимумКомплекта) + ". Это НЕ свободные места и не число текущих пользователей.");
        Строки.Добавить(Сопоставление);
        Строки.Добавить("Адрес получения: " + ?(СвойЛокальныйАдрес85(Адрес), "собственный локальный", "не сопоставлен; никуда не подключаемся")
            + "; reported IP-порт=" + Строка(Порт) + ". Порт0 сам по себе не объявляется ошибкой клиента.");
        Строки.Добавить("FileName скрыт; заполнен=" + Строка(ФайлЛицензии <> "") + "; серия/регномер скрыты; заполнены=" + Строка(Серия <> ""));
        Строки.Добавить("Локализованные представления скрыты; краткое заполнено=" + Строка(Краткое <> "")
            + ", длина=" + Строка(СтрДлина(Краткое)) + "; подробное заполнено=" + Строка(Подробное <> "") + ", длина=" + Строка(СтрДлина(Подробное)));
        Если Предупреждения.Количество() > 0 Тогда
            Строки.Добавить(СтрСоединить(Предупреждения, Символы.ПС));
        КонецЕсли;
        ПоляОтпечатка = Новый Массив;
        Для Каждого Пара Из Новый Структура("Адрес,PID,Файл,Краткое,Максимум,МаксимумКомплекта,Подробное,ОтСервера,Порт,Программная,Серия,Сетевая",
            Адрес, PID, ФайлЛицензии, Краткое, Максимум, МаксимумКомплекта, Подробное, ОтСервера, Порт, Программная, Серия, Сетевая) Цикл
            ПоляОтпечатка.Добавить(Строка(Пара.Значение));
        КонецЦикла;
        Отпечатки.Добавить().Отпечаток = ЗакрытыйОтпечатокСвоихЗначений85(ПоляОтпечатка);
    КонецЦикла;
    Повторный = НайтиТолькоСвойСеанс85(Кластер, БазаUUID, СеансUUID);
    Если Повторный.ИдентификаторПроцесса <> Сеанс.ИдентификаторПроцесса Тогда
        ВызватьИсключение "Привязка actual сеанса к рабочему UUID изменилась между чтениями; предыдущий отчёт сохраняется";
    КонецЕсли;
    Если Лицензии.Количество() = 0 Тогда
        Строки.Добавить("Список пуст. Native сведения о клиентской лицензии не получены; никакой фиктивный элемент не создаётся и юридический вывод не делается.");
    КонецЕсли;
    Отпечатки.Сортировать("Отпечаток");
    СписокОтпечатков = Новый Массив;
    Для Каждого СтрокаОтпечатка Из Отпечатки Цикл
        СписокОтпечатков.Добавить(СтрокаОтпечатка.Отпечаток);
    КонецЦикла;
    ЗакрытыйОтпечаток = ЗакрытыйОтпечатокСвоихЗначений85(СписокОтпечатков);
    Строки.Добавить("Чтение завершено: " + Формат(ТекущаяДата(), "ДФ=yyyy-MM-dd HH:mm:ss") + ". Это не атомарный snapshot сервера.");
    Возврат Новый Структура("КластерUUID,БазаUUID,СеансUUID,ЗакрытыйОтпечаток,Отчет", Кластер.ИдентификаторКластера,
        База.ИдентификаторИнформационнойБазы, Сеанс.ИдентификаторСеанса, ЗакрытыйОтпечаток, СтрСоединить(Строки, Символы.ПС));
КонецФункции

Функция ЗакрытыйОтпечатокСвоихЗначений85(Значения)
    Хеш = Новый ХешированиеДанных(ХешФункция.SHA256);
    Для Каждого Текст Из Значения Цикл
        Хеш.Добавить(Формат(СтрДлина(Текст), "ЧГ=0;ЧДЦ=0") + ":" + Текст);
    КонецЦикла;
    Возврат Base64Строка(Хеш.ХешСумма);
КонецФункции

Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

#КонецЕсли
Полный модуль своего толстого управляемого target-клиента: настоящий номер серверного сеанса

Своя CF УчебныеЛицензии85Клиент → Обработка УчебныйКлиент85 → Основная управляемая форма → модуль формы. Native ПриОткрытии(Отказ); серверный вызов без контекста только читает проверенный собственный сеанс.

Самостоятельная управляемая форма собственных target-ИБ и пользователя; клиентское ПриОткрытии(Отказ) и серверные процедуры компилируются в отдельных native контекстах. Никаких административных вызовов в этом модуле.

#Если ТолстыйКлиентУправляемоеПриложение Или Сервер Тогда

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Тогда
        Отказ = Истина;
        ВызватьИсключение "Только собственный target-клиент в VM OWN-LIC85";
    КонецЕсли;
    Номер = ПроверитьСвойСерверныйСеанс85();
    Состояние85 = "Собственный target-клиент. Номер сеанса=" + Строка(Номер)
        + ". Это НЕ UUID сеанса и НЕ OS PID. Оставьте форму открытой, сопоставьте UUID в своей консоли RAS, PID собственного 1cv8.exe вручную в Диспетчере задач.";
КонецПроцедуры

&НаСервереБезКонтекста
Функция ПроверитьСвойСерверныйСеанс85()
    ПроверитьСвойПустойСтенд();
    Если ВРег(ИмяКомпьютера()) <> "OWN-LIC85" Или ИмяПользователя() <> "Лицензии85Клиент" Тогда
        ВызватьИсключение "Свой серверный сеанс должен принадлежать VM и target-пользователю";
    КонецЕсли;
    Части = СтрРазделить(СтрокаСоединенияИнформационнойБазы(), ";");
    Если Части.Количество() <> 2 И Части.Количество() <> 3 Тогда
        ВызватьИсключение "Target connection содержит только один Srvr и один Ref";
    КонецЕсли;
    СерверНайден = Ложь;
    БазаНайдена = Ложь;
    Для Каждого Часть Из Части Цикл
        Параметр = СокрЛП(Часть);
        Если НРег(Параметр) = "srvr=""127.0.0.1:15441""" Тогда
            Если СерверНайден Тогда
                ВызватьИсключение "Повторный Srvr не допускается";
            КонецЕсли;
            СерверНайден = Истина;
        ИначеЕсли НРег(Параметр) = "ref=""учебныйклиентлицензий85_0f605d14""" Тогда
            Если БазаНайдена Тогда
                ВызватьИсключение "Повторный Ref не допускается";
            КонецЕсли;
            БазаНайдена = Истина;
        ИначеЕсли Параметр <> "" Тогда
            ВызватьИсключение "Target connection должна содержать только точные собственные Srvr/Ref";
        КонецЕсли;
    КонецЦикла;
    Если Не СерверНайден Или Не БазаНайдена Тогда
        ВызватьИсключение "Target-клиент подключён не к exact собственному серверу/имени ИБ";
    КонецЕсли;
    Возврат НомерСеансаИнформационнойБазы();
КонецФункции

&НаСервереБезКонтекста
Процедура ПроверитьСвойПустойСтенд()
    Если Метаданные.Справочники.Количество() <> 0 Или Метаданные.Документы.Количество() <> 0 Или Метаданные.Перечисления.Количество() <> 0 Или Метаданные.РегистрыСведений.Количество() <> 0 Или Метаданные.РегистрыНакопления.Количество() <> 0 Или Метаданные.РегистрыБухгалтерии.Количество() <> 0 Или Метаданные.РегистрыРасчета.Количество() <> 0 Или Метаданные.ПланыВидовХарактеристик.Количество() <> 0 Или Метаданные.ПланыВидовРасчета.Количество() <> 0 Или Метаданные.ПланыСчетов.Количество() <> 0 Или Метаданные.ПланыОбмена.Количество() <> 0 Или Метаданные.Последовательности.Количество() <> 0 Или Метаданные.БизнесПроцессы.Количество() <> 0 Или Метаданные.Задачи.Количество() <> 0 Или Метаданные.ОбщиеРеквизиты.Количество() <> 0 Или Метаданные.ПодпискиНаСобытия.Количество() <> 0 Или Метаданные.РегламентныеЗадания.Количество() <> 0 Или Метаданные.ВнешниеИсточникиДанных.Количество() <> 0 Тогда
        ВызватьИсключение "Нужен только свой новый пустой учебный стенд";
    КонецЕсли;
    Если Метаданные.ЕстьИзмененияРасширениямиКонфигурации() Тогда
        ВызватьИсключение "Свой сеанс не должен изменяться расширениями";
    КонецЕсли;
    Источники = Новый Массив;
    Источники.Добавить(ИсточникРасширенийКонфигурации.БазаДанных);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансАктивные);
    Источники.Добавить(ИсточникРасширенийКонфигурации.СеансОтключенные);
    Для Каждого Источник Из Источники Цикл
        Расширения = РасширенияКонфигурации.Получить(, Источник);
        Если ТипЗнч(Расширения) <> Тип("Массив") Тогда
            ВызватьИсключение "Native список расширений должен иметь тип Массив";
        КонецЕсли;
        Если Расширения.Количество() <> 0 Тогда
            ВызватьИсключение "В своём новом стенде нет расширений базы или сеанса";
        КонецЕсли;
    КонецЦикла;
    Если ТранзакцияАктивна() Тогда
        ВызватьИсключение "Чужая или вложенная активная транзакция не допускается";
    КонецЕсли;
КонецПроцедуры

#КонецЕсли

Разбор по шагам

  1. Own guard останавливает чужую CF/VM/connection и неверную версию ещё до RAS. Кластер, ИБ и сеанс выбираются только из настоящих native списков; одиночность не заменяет проверки exact actual UUID/name/host/port/user/номер/тип приложения. Отсутствие или лишний объект означает отказ, не выбор первого доступного чужого элемента.

  2. Клиентская лицензия приходит именно из Сеанс.Лицензии. Native страница АдминистрированиеЛицензия приводит этот RAS-маршрут. У типа нет конструктора; каждый actual элемент массива проверяется на этот тип. Пустой массив — отдельный честный результат без фиктивного примера или вывода о действительности.

  3. Связь рабочего процесса определяется UUID сеанса ИдентификаторПроцесса → рабочего процесса ИдентификаторРабочегоПроцесса. После этого его ИдентификаторПроцесса — уже Строка OS PID. С PID лицензии сравнивается только OS PID: вручную подтверждённый клиентский либо связанный серверный. Возможный другой серверный процесс получения лицензии не объявляется чужим или недействительным только из-за несовпадения с rphost.

  4. Все 12 native readonly полей сначала считываются из actual элемента в память с проверкой документированных типов. SoftwareLicense классифицирует программную/аппаратную лицензию; NetworkKey имеет смысл аппаратного сетевого Aladdin-ключа. RetrievedByServer отделяет полученную сервером и выданную клиенту лицензию от полученной клиентским приложением.

  5. MaxUsers — предел используемого ключа или файла, MaxSoftwareLicenseUsers — предел программного комплекта, а для аппаратного должен совпадать с первым по справке. Ни количество сведений в массиве, ни эти два предела не являются свободными местами/текущими пользователями. Неожиданное сочетание — диагностическое предупреждение, не юридический вердикт.

  6. АдресСервера и ПортСервера относятся к процессу получения лицензии, не автоматически к RAS18585 или manager15441. Для несопоставленного адреса выводится только эта классификация: никакого подключения к нему. Порт0 у client-полей сам по себе не объявляется ошибкой. Raw адрес/PID/путь/серия в отчёт не попадают.

  7. FileName и KeySeries не выводятся: отчёт показывает только заполненность. Brief/DetailedPresentation локализованы и могут содержать приватные данные; выводятся лишь заполненность/длина, без разбора по строковым словам, regex или отображения полного значения. PIN никогда не читается и не требуется.

  8. Для каждого набора 12 полей рассчитывается private SHA256 с длиной каждого добавленного значения перед текстом. Множество элементов сортируется по private отпечаткам с сохранением повторов; набор сравнивается независимо от порядка массива. Ни raw поля, ни отпечатки не сериализуются и не печатаются, сохраняется только private память формы.

  9. Непосредственно после чтения повторно ищется тот же native сеанс; исчезнувший сеанс или изменившийся рабочий UUID прерывает принятие результата. Это не блокировка сервера, не лицензирующая транзакция и не доказательство атомарности набора readonly getter.

  10. ПрочитатьПервыйСнимок85 сохраняет только первый private fingerprint и безопасный отчёт. СравнитьВтороеЧтение85 создаёт новый native acquisition того же actual кластера/ИБ/сеанса и реально читает лицензии снова. Результат — совпали/различаются значения двух наблюдений, НЕ проверена юридическая действительность/подпись/право владения. Ошибка оставляет старый отчёт, очищает пароли и не печатает native exception с возможными приватными деталями.

Как проверить результат

  1. Отчёт показывает реальный вид/источник получения, два разных предела и masked presence/length каждого строкового поля; точные номера регистрации, файл лицензии и локализованные представления отсутствуют.

  2. Сверьте сами в приватной консоли только выбранного собственного сеанса: software/hardware/network, client/server получение и capacity соответствуют native полям. Raw private значения никому не пересылайте.

  3. Два последовательных чтения одного незаменённого собственного сеанса могут совпасть или различаться по реальным live данным. Оба исхода корректны; равенство не доказывает атомарность или validity, различие не объявляется дефектом лицензии.

  4. Негативные безопасные проверки своего стенда: пустой пароль/UUID, вместо actual UUID ввести короткий номер сеанса, закрыть свой target-клиент до второго чтения. Пульт должен отказаться, сохранив предыдущий отчёт. Только если native ПолученаСервером=Ложь, отдельно введите собственный PID пульта вместо target-клиента: ожидается PID не сопоставлен. При server issuance сопоставляется серверный PID и этот клиентский PID не используется как доказательство. Чужую лицензию не подключайте ради теста.

  5. Повторное чтение после нового сеанса требует отдельно скопировать его actual UUID и выполнить первое чтение, а не подменить старый. При нуле native license элементов выводится пустой список, не выдуманный объект.

  6. Сверьте supporting target номер с консолью: это номер сеанса, не PID/UUID. Номер и client application1CV8 относятся к выбранному собственному толстому управляемому target-клиенту, не к обычному файловому пульту.

Ожидаемый результат

Собственный административный отчёт классифицирует actual сведения одной учебной клиентской лицензии/набора и безопасно сопоставляет два наблюдения одного настоящего сеанса, не устанавливая и не меняя лицензии.

На что обратить внимание

  1. Все административные вызовы в примере — future manual код для собственного стенда. Автор не запускал RAS/COM/системные вызовы/1С/сеть или установку лицензий; выполнялись лишь source authoring и статические тесты. Root/config/production read-only, новых backups/archives нет.

  2. Юридические права и разрешённое использование подтверждает владелец стенда вне программы. Getter, лицензия в массиве, PID совпадение и SHA256 fingerprint этого не доказывают. Эта программа не проверяет файл .lic, подпись или истечение срока.

  3. АдминистрированиеРабочийПроцесс.Лицензии описывает серверные лицензии процесса, а Сеанс.Лицензии — клиентские лицензии сеанса. Здесь применяется именно второй источник; считать массивы взаимозаменяемыми нельзя.

  4. Все свойства АдминистрированиеЛицензия readonly. PID лицензии — Строка OS PID; UUID сеанса/рабочего процесса — УникальныйИдентификатор. Нельзя выдумывать UUID, присваивать fields или напрямую сравнивать эти разные домены.

  5. Repeated native reads неатомарны. Проверка неизменной идентичности в конце уменьшает очевидное устаревание, но не доказывает одновременность всех полей или отсутствие событий между чтениями.

  6. Full Detailed/BriefPresentation и KeySeries/FileName могут раскрыть private сведения. Даже hash не является шифрованием/доказательством владения; здесь он private только для сравнения и не публикуется.

  7. Пульт не сохраняет файлы/JSON, не открывает .lic, не получает PIN/регистрационный secret и не выполняет лицензирующие mutation. Для неизвестного адреса ничего не подключается. Не адаптируйте этот пример для сбора лицензий рабочего общего кластера.

Пример не запускался в вашей базе. Перед применением проверьте его в указанном учебном контексте.

Не хотите разбираться сами?

Адаптируем это решение под вашу базу. Оценка бесплатно.

Оставить задачу

1С, 1С:Предприятие — товарные знаки ООО «1С». Сайт не является официальным представительством фирмы «1С» и не аффилирован с ней.