- Регистрация
- 01.05.2014
- Сообщения
- 228
- Реакции
- 221
- Баллы
- 43
Всем привет, хоть я сейчас и загружен очень сильно на проекте по телеграм, да еще и сопли по колено, нашел таки время отписать коротенькую статейку по поводу защиты своих шаблонов.
Интро:
Весь код, который тут представлен, написан на C# за исключением скриптов гугл ). Тем кто не разбирается в Шарпе, рекомендую уделить время по изучать его, ну или использовать готовое решение в своих целях. Я сам так часто поступаю
.
Интро2:
Сидел писал статью и на Складчике пришло уведомление, что появился новый ответ в отслеживаемой теме, как оказалось апнули довольно старую тему по защите шаблонов от уважаемого @Moadip, оценив его идею и свои наработки пришел к выводу, что скорее всего он меня натолкнул на этот краеугольный камень ))). Отмечу что наши идеи схожи, но реализации разные.
Стартуем:
Итак, с чего начнем - для тех кто не знает, шаблоны можно зашифровать и установить в них права стандартным модулем zennoposter "Шифрование"
Казалось бы этого достаточно, но не тут то было )) многие, кто оказывает услуги по разработке шаблонов, сталкивались с нерадивыми заказчиками, которые получали решение, а оплачивать отказывались; пару топиков тут уже проскакивали с гневом шаблонописцев. Что делать? Можно воспользоваться личным кабинетом, разделом боты и не заморачиваться
для тех кто не в курсе смотреть сюда https://userarea.zennolab.com/lk/login.aspx
- Ну вот теперь та проблема решена же!
Да, можно и так защитить свой труд, но ведь все мы ушлые ребятки и не хотим морозить 10-20-100 баксов на счету в ЛК ЗенноЛаба (@nuaru ни чего личного
. Я просто хочу рассказать, что делаю сам и ни в коей мере не призываю отказаться от выписки шаблонов через ЛК! )
А мы с вами тем временем пойдем по другому пути. Итак, давайте создадим пустой проект и накидаем в него пару кубиков
, ну 3 если быть точным.
Думаю тут нет вопросов ни у кого...
Идем далее, давайте подумаем как бы нам защищаться, та?
Самый очевидный путь собрать какие то данные из окружения зенки и/или ПК и что-то с ними сделать.
На ум приходит сразу то, что зенка привязана к e-mail, который не меняется. Давайте его и будем использовать.
А как нам его получить? Да очень просто:
Да все верно, выдираем из реестра почту привязанную к зенке!
Думаем дальше:
Хочу, чтобы я мог ограничивать работу шаблона в каком то периоде: часы, дни, годы. Ну и отлично
Значит, нам нужно сохранять дату каким-то образом.
О! Забыли подумать над тем, что на каждом компе время может отличаться(разные часовые пояса), ну для этого у наст есть стандартизация времени по-Гринвичу и, чтобы получить текущую дату по Гринвичу, нужно выполнить такой код:
Почитайте те, кто не знаком с классом DateTime https://msdn.microsoft.com/ru-ru/library/k494fzbf(v=vs.100).aspx - узнаете много интересного!
Отличненько, что далее?
Теперь нам нужно каким-то образом где-то проверить, а может шаблон работать или нет. Другими словами, нам нужно где-то что-то посмотреть и узнать, что шаблон может запускаться.
Ну, так давайте уже знакомиться с сервисом google script app!
Сперва создадим пустую гугл табличку и посмотрим на вкладку инструменты:
Конечно же тыкайте на "Редактор скриптов", я думал вы уже тыкнули
. Главное потом нажмите сюда
У вас, скорее всего, там будет пусто, а у меня уже есть пару боевых скриптов.
Полагаю, что вы же ткнули "Создание проекта" и увидели вот такую картинку:
стираем там все, что написано и пишем код:
Как вы уже заметили, тут две функции: пустых, которые обрабатывают различные события, соответственно doGet - обрабатывает гет запросы к нашему скрипту, а doPost - пост запросы.
Что дальше? А давайте исправим doGet так, чтобы он нам возвращал те данные, которые мы ему передали. Исправьте скрипт следующим образом:
Немного пояснений:
Как вы видите из кода, функция doGet принимает один объект - e, который содержит в себе все параметры, переданные запросом в УРЛ. В нашем случае использовано 2 параметра mail и date.
Ну вот, пришла пора выставить скрипт наружу. Для этого сделаем следующее:
Нажмем на кнопку.
Теперь выполним следующие действия:
Версия: новый
Как запускать: От моего имени
Кто имеет доступ: Все, включая анонимных
И, нажимаем "Развернуть", после чего гугл попросит нас подтвердить разрешение на внесение изменений, мы, конечно же, соглашаемся! А может и не попросит
У меня перестал просить, наверное от того, что я все скрипты храню в одной таблице.
Копируем урл скрипта. Он появится в отдельном окошке, но если вы забыли его скопировать, то нажмите "Публикация" - "Развернуть как веб приложение" и вверху увидите заветный УРЛ скрипта.
ВАЖНО! Если вы внесли какие-то изменения в скрипт, то вам нужно провести процедуру публикации и указать версию "НОВЫЙ".
Для тех, кто любит читать по Англицки, кидаю фулдок по веб АПП https://developers.google.com/apps-script/guides/web
Урл скопировали, давайте вернемся к шаблону.
В кубик C# добавим такой код, запустим его на выполнение и посмотрим, что получили:
Вставили? Запустили? Получили свой емаил и текущую дату?
Отлично! Двигаемся далее.
Действиями выше, мы связали зенку с GAS. Теперь, давайте думать, что у нас будет в бэкэнде - содержание гугл таблички.
Очевидно, что в табличке мы должны хранить электронный адрес клиента, дату, до которой он может пользоваться шаблоном, а так же название шаблона. Вот такую табличку давайте и сделаем.
Как вы видите на скрине, я добавил еще одно поле - "HASH". А зачем спросите вы? Так будет проще искать нужную строчку в таблице. Т.е. вместо того, чтобы делать два запроса к таблице (Сначала найдем все строки по полю Client, а потом из этих строк будем искать TemplateName), мы будем искать по одному полю под названием "HASH", а значение этого поля будет рассчитано таким образом:
То бишь соединим строковое значения емайл адреса клиента и название шаблона, и возьмем хэш от полученной строки!
ОК! Теперь давайте научим наш гугло скрипт искать данные в таблице, а для этого нам потребуется немного изменить его следующим образом:
Скрипт мы поправили, теперь давайте немного под шаманим шаблон, заменим содержимое C# кубика следующим содержанием:
А мы все ближе! К чему? ....
Что теперь мы получаем? а мы получаем JSON в котором описан наш клиент, ну вы в данном случае. Это отлично! Но мы сразу позаботимся о том что, возможна ситуация когда клиента нет в списке клиентов. И если мы не смогли найти по хешу клиента тогда шаблон получит вот такой JSON:
Давайте его обработаем, и для этого изменим в C# кубике все строки на код ниже:
Лирическое отступление для тех кто все проделывает шаг за шагом:
Чтобы у вас все заработало вам нужно в шаблоне добавить модуль "Добавить ссылки из GAC", и добавить либу "System.Web.Extensions", я нарисовал путь мышкой на скриншоте:
Я кукарача! )))))))))))))))
Думаем далее! Мы общаемся с нашим "Сервером" лицензирования, нашим "Софтом", но все что мы передаем ему, мы передаем в открытом виде, все параметры можно подделать и сломать нашу систему защиты. Я не буду объяснять как это сделать, я расскажу как от этого защитится.
Короче так, мы нашему серверу, вы заметили, я стал называть скрипт в гугло табличке сервером лицензирования, это не спроста. И так нашему серверу поступают данные: емаил, дата текущая и хеш. Как нам должен ответить сервер чтобы избежать подделки данных? - а все просто: Сервер должен возвращать в ответе хеш доступа и состояние лицензии. Давайте подумаем как....
А давайте, наш сервер будет высчитывать количество секунд, которое осталось по его данным на использование шаблона. Но не просто так, а в виде какого нибудь хеша. И вот тут мы понимаем что гугло скрипты особо та и не умеют рассчитывать стойки МД5. Но это поправимо. Добавьте код приведенный ниже в наш гугло скрипт.
Этот код я сдернул в сети, с какого-то сайта очень древней наружности, и разбирать его мы с вами не будем, скажу одно он позволяет получить хешь от обекта, что нас устаревает на 100500%!
Ну так что на счет расчетов? Давайте думать: мы знаем текущее время у клиента, так как передаем его в запросе, мы знаем время когда кончится лицензия у клиента, это хранится в таблице. Ну так давайте получим разницу этих дат в секундах, и от полученного возьмем хеш. Для этого исправим код гугл скрипта на следующий:
И внесем исправления в код кубика C# всамом шаблоне:
Вот ребятки такая штука получилась. Шаблон и текст гугло скрипта приложу.
Интро:
Весь код, который тут представлен, написан на C# за исключением скриптов гугл ). Тем кто не разбирается в Шарпе, рекомендую уделить время по изучать его, ну или использовать готовое решение в своих целях. Я сам так часто поступаю
.Интро2:
Сидел писал статью и на Складчике пришло уведомление, что появился новый ответ в отслеживаемой теме, как оказалось апнули довольно старую тему по защите шаблонов от уважаемого @Moadip, оценив его идею и свои наработки пришел к выводу, что скорее всего он меня натолкнул на этот краеугольный камень ))). Отмечу что наши идеи схожи, но реализации разные.
Стартуем:
Итак, с чего начнем - для тех кто не знает, шаблоны можно зашифровать и установить в них права стандартным модулем zennoposter "Шифрование"
Казалось бы этого достаточно, но не тут то было )) многие, кто оказывает услуги по разработке шаблонов, сталкивались с нерадивыми заказчиками, которые получали решение, а оплачивать отказывались; пару топиков тут уже проскакивали с гневом шаблонописцев. Что делать? Можно воспользоваться личным кабинетом, разделом боты и не заморачиваться
для тех кто не в курсе смотреть сюда https://userarea.zennolab.com/lk/login.aspx
- Ну вот теперь та проблема решена же!
Да, можно и так защитить свой труд, но ведь все мы ушлые ребятки и не хотим морозить 10-20-100 баксов на счету в ЛК ЗенноЛаба (@nuaru ни чего личного
. Я просто хочу рассказать, что делаю сам и ни в коей мере не призываю отказаться от выписки шаблонов через ЛК! )А мы с вами тем временем пойдем по другому пути. Итак, давайте создадим пустой проект и накидаем в него пару кубиков
, ну 3 если быть точным.
Думаю тут нет вопросов ни у кого...
Идем далее, давайте подумаем как бы нам защищаться, та?
Самый очевидный путь собрать какие то данные из окружения зенки и/или ПК и что-то с ними сделать.
На ум приходит сразу то, что зенка привязана к e-mail, который не меняется. Давайте его и будем использовать.
А как нам его получить? Да очень просто:
Код:
return Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\ZennoLab").GetValue("login").ToString();
Да все верно, выдираем из реестра почту привязанную к зенке!
Думаем дальше:
Хочу, чтобы я мог ограничивать работу шаблона в каком то периоде: часы, дни, годы. Ну и отлично
Значит, нам нужно сохранять дату каким-то образом.О! Забыли подумать над тем, что на каждом компе время может отличаться(разные часовые пояса), ну для этого у наст есть стандартизация времени по-Гринвичу и, чтобы получить текущую дату по Гринвичу, нужно выполнить такой код:
Код:
return DateTime.UtcNow.ToString("MM/dd/yyyy HH:mm");
Почитайте те, кто не знаком с классом DateTime https://msdn.microsoft.com/ru-ru/library/k494fzbf(v=vs.100).aspx - узнаете много интересного!

Отличненько, что далее?
Теперь нам нужно каким-то образом где-то проверить, а может шаблон работать или нет. Другими словами, нам нужно где-то что-то посмотреть и узнать, что шаблон может запускаться.
Ну, так давайте уже знакомиться с сервисом google script app!
Сперва создадим пустую гугл табличку и посмотрим на вкладку инструменты:
Конечно же тыкайте на "Редактор скриптов", я думал вы уже тыкнули
. Главное потом нажмите сюда
У вас, скорее всего, там будет пусто, а у меня уже есть пару боевых скриптов.
Полагаю, что вы же ткнули "Создание проекта" и увидели вот такую картинку:
стираем там все, что написано и пишем код:
Java:
function doPost() {
}
function doGet() {
}
Как вы уже заметили, тут две функции: пустых, которые обрабатывают различные события, соответственно doGet - обрабатывает гет запросы к нашему скрипту, а doPost - пост запросы.
Что дальше? А давайте исправим doGet так, чтобы он нам возвращал те данные, которые мы ему передали. Исправьте скрипт следующим образом:
Java:
function doPost(e) {
}
function doGet(e) {
var s = e.parameter.mail + " " + e.parameter.date;
//строчка ниже просто возвращает то, что пришло гет запросом
return ContentService.createTextOutput(s).setMimeType(ContentService.MimeType.TEXT);
}
Немного пояснений:
Как вы видите из кода, функция doGet принимает один объект - e, который содержит в себе все параметры, переданные запросом в УРЛ. В нашем случае использовано 2 параметра mail и date.
Ну вот, пришла пора выставить скрипт наружу. Для этого сделаем следующее:
Нажмем на кнопку.
Теперь выполним следующие действия:
Версия: новый
Как запускать: От моего имени
Кто имеет доступ: Все, включая анонимных
И, нажимаем "Развернуть", после чего гугл попросит нас подтвердить разрешение на внесение изменений, мы, конечно же, соглашаемся! А может и не попросит
У меня перестал просить, наверное от того, что я все скрипты храню в одной таблице.Копируем урл скрипта. Он появится в отдельном окошке, но если вы забыли его скопировать, то нажмите "Публикация" - "Развернуть как веб приложение" и вверху увидите заветный УРЛ скрипта.
ВАЖНО! Если вы внесли какие-то изменения в скрипт, то вам нужно провести процедуру публикации и указать версию "НОВЫЙ".
Для тех, кто любит читать по Англицки, кидаю фулдок по веб АПП https://developers.google.com/apps-script/guides/web
Урл скопировали, давайте вернемся к шаблону.
В кубик C# добавим такой код, запустим его на выполнение и посмотрим, что получили:
C#:
//Где опубликован скрипт
string licUrl = "https://script.google.com/ ТУТ ДОЛЖЕН БЫТЬ УРЛ ВАШЕГО СКРИПТА";
//Параметры полученые шаблоном
string mail = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\ZennoLab").GetValue("login").ToString();
string date = DateTime.UtcNow.ToString("MM/dd/yyyy HH:mm");
//Форматируем параметры
string parameter = string.Format("?mail={0}&date={1}", mail, date);
//отправляем запрос
string response = ZennoPoster.HttpGet(licUrl + parameter, "", "UTF-8", InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
return response;
Вставили? Запустили? Получили свой емаил и текущую дату?
Отлично! Двигаемся далее.
Действиями выше, мы связали зенку с GAS. Теперь, давайте думать, что у нас будет в бэкэнде - содержание гугл таблички.
Очевидно, что в табличке мы должны хранить электронный адрес клиента, дату, до которой он может пользоваться шаблоном, а так же название шаблона. Вот такую табличку давайте и сделаем.
Как вы видите на скрине, я добавил еще одно поле - "HASH". А зачем спросите вы? Так будет проще искать нужную строчку в таблице. Т.е. вместо того, чтобы делать два запроса к таблице (Сначала найдем все строки по полю Client, а потом из этих строк будем искать TemplateName), мы будем искать по одному полю под названием "HASH", а значение этого поля будет рассчитано таким образом:
C#:
return Convert.ToString(mail + project.Name).GetMD5Hash();
То бишь соединим строковое значения емайл адреса клиента и название шаблона, и возьмем хэш от полученной строки!
ОК! Теперь давайте научим наш гугло скрипт искать данные в таблице, а для этого нам потребуется немного изменить его следующим образом:
Java:
function doGet(e) {
var h = e.parameter.HASH; // возмем хешь из параметров
var client = getClientPermit(h); // найдем клиента
return ContentService.createTextOutput(JSON.stringify(client)).setMimeType(ContentService.MimeType.TEXT);//ответим шаблону
}
//Получим разрешение
function getClientPermit(h){
//вот прям ща создадим объект в который сложим результат поиска пользователя
var Clients = getClientsObject(getTebleRows().getDataRange().getValues()); //Прочитаем все таблицу
return searchClientFromClientsHASH(h, Clients); //вернем объект
}
//Эта функция создает удобный для нас массив объектов содержащий строки таблички
function getClientsObject(range) {
var rowObjects = [];
for (var i = 1; i < range.length; i++) {
var row = {Client: range[i][0], ExpiredDate: range[i][1], TemplateName: range[i][2], HASH:range[i][3]};
rowObjects.push(row);
}
return rowObjects;
}
//Эта функция ищет нам данные о клиенте по хешу
function searchClientFromClientsHASH(hash, Clients){
for (var i = 0; i < Clients.length; i++) {
if (Clients[i].HASH == hash)
return Clients[i];
}
return {error: 'Клиент не найден!', code: 0};
}
function getTebleRows(){
// Откроем таблицу по ИД
var tid = 'вставьте свой'; // это ид таблицы, он берется из урл самой таблицы
var sheet = SpreadsheetApp.openById(tid).getSheetByName('Clients');
return sheet;
}
Скрипт мы поправили, теперь давайте немного под шаманим шаблон, заменим содержимое C# кубика следующим содержанием:
C#:
//Где опубликован скрипт, я думаю понятно что нужно вставить урл вашего скрипта
string licUrl = "https://script.google.com/a/zhag/ваш ид скрипта/exec";
//Параметры полученые шаблоном
string mail = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\ZennoLab").GetValue("login").ToString();
string date = DateTime.UtcNow.ToString("MM/dd/yyyy HH:mm");
//Форматируем параметры
string parameter = string.Format("?mail={0}&date={1}&HASH={3}", mail, date, Convert.ToString(mail + project.Path));
//отправляем запрос
string response = ZennoPoster.HttpGet(licUrl + parameter, "", "UTF-8", InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
return response;
А мы все ближе! К чему? ....
Что теперь мы получаем? а мы получаем JSON в котором описан наш клиент, ну вы в данном случае. Это отлично! Но мы сразу позаботимся о том что, возможна ситуация когда клиента нет в списке клиентов. И если мы не смогли найти по хешу клиента тогда шаблон получит вот такой JSON:
Код:
{"error":"Клиент не найден!","code":0}
Давайте его обработаем, и для этого изменим в C# кубике все строки на код ниже:
C#:
JavaScriptSerializer ser = new JavaScriptSerializer();
//Где опубликован скрипт
string licUrl = "https://script.google.com/a/z";
//Параметры полученые шаблоном
string mail = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\ZennoLab").GetValue("login").ToString();
string date = DateTime.UtcNow.ToString("MM/dd/yyyy HH:mm");
//Форматируем параметры
string parameter = string.Format("?mail={0}&date={1}&HASH={3}", mail, date, Convert.ToString(mail + project.Path));
//отправляем запрос
string response = ZennoPoster.HttpGet(licUrl + parameter, "", "UTF-8", InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
//Сделаем словарь из ответа нашего гугл скрипта
Dictionary<string, dynamic> d = ser.Deserialize<Dictionary<string, dynamic>>(response);
//проверем чтобы мы нашли клиента 100%
if(d.ContainsKey("error")){//Если не нашли клиента
ZennoPoster.StopTask(Guid.Parse(project.TaskId)); // остановим выполнение шаблона
throw new Exception(d["error"] + " Oбратитесь в телеграм к разработчику @zhagru");
}
return response;
Лирическое отступление для тех кто все проделывает шаг за шагом:
Чтобы у вас все заработало вам нужно в шаблоне добавить модуль "Добавить ссылки из GAC", и добавить либу "System.Web.Extensions", я нарисовал путь мышкой на скриншоте:
Я кукарача! )))))))))))))))
Думаем далее! Мы общаемся с нашим "Сервером" лицензирования, нашим "Софтом", но все что мы передаем ему, мы передаем в открытом виде, все параметры можно подделать и сломать нашу систему защиты. Я не буду объяснять как это сделать, я расскажу как от этого защитится.
Короче так, мы нашему серверу, вы заметили, я стал называть скрипт в гугло табличке сервером лицензирования, это не спроста. И так нашему серверу поступают данные: емаил, дата текущая и хеш. Как нам должен ответить сервер чтобы избежать подделки данных? - а все просто: Сервер должен возвращать в ответе хеш доступа и состояние лицензии. Давайте подумаем как....
А давайте, наш сервер будет высчитывать количество секунд, которое осталось по его данным на использование шаблона. Но не просто так, а в виде какого нибудь хеша. И вот тут мы понимаем что гугло скрипты особо та и не умеют рассчитывать стойки МД5. Но это поправимо. Добавьте код приведенный ниже в наш гугло скрипт.
Java:
String.prototype.MD5 = function(charset, toByte) {
charset = charset || Utilities.Charset.UTF_8;
var digest = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, this, charset);
if(toByte) return digest;
var __ = '';
for (i = 0; i < digest.length; i++) {
var byte = digest[i];
if (byte < 0) byte += 256;
var bStr = byte.toString(16);
if (bStr.length == 1) bStr = '0' + bStr;
__ += bStr;
}
return __;
}
Этот код я сдернул в сети, с какого-то сайта очень древней наружности, и разбирать его мы с вами не будем, скажу одно он позволяет получить хешь от обекта, что нас устаревает на 100500%!
Ну так что на счет расчетов? Давайте думать: мы знаем текущее время у клиента, так как передаем его в запросе, мы знаем время когда кончится лицензия у клиента, это хранится в таблице. Ну так давайте получим разницу этих дат в секундах, и от полученного возьмем хеш. Для этого исправим код гугл скрипта на следующий:
Java:
function doGet(e) {
var salt = "сольМоя"; //это дополнителная строка которую добовляем при получении хеша, чтоб его ни кто не мог расчитать без нас
var h = e.parameter.HASH; // возмем хешь из параметров
var client = getClientPermit(h); // найдем клиента
var sicret = salt.MD5() + getSecondsWork(client.ExpiredDate, e.parameter.date).toString().MD5();// составим сикретные данные
client.s = sicret; // добавим хеш к ответу сервера
return ContentService.createTextOutput(JSON.stringify(client)).setMimeType(ContentService.MimeType.TEXT);//ответим шаблону
}
//Получим разрешение
function getClientPermit(h){
//вот прям ща создадим объект в который сложим результат поиска пользователя
var Clients = getClientsObject(getTebleRows().getDataRange().getValues()); //Прочитаем все таблицу
return searchClientFromClientsHASH(h, Clients); //вернем объект
}
//Эта функция создает удобный для нас массив объектов содержащий строки таблички
function getClientsObject(range) {
var rowObjects = [];
for (var i = 1; i < range.length; i++) {
var row = {Client: range[i][0], ExpiredDate: range[i][1], TemplateName: range[i][2], HASH:range[i][3]};
rowObjects.push(row);
}
return rowObjects;
}
//Эта функция ищет нам данные о клиенте по хешу
function searchClientFromClientsHASH(hash, Clients){
for (var i = 0; i < Clients.length; i++) {
if (Clients[i].HASH == hash)
return Clients[i];
}
return {error: 'Клиент не найден!', code: 0};
}
function getTebleRows(){
// Откроем таблицу по ИД
var tid = 'вставьСвойИдТаблици'; // это ид таблицы, он берется из урл самой таблицы
var sheet = SpreadsheetApp.openById(tid).getSheetByName('Clients');
return sheet;
}
//Расчитаем сколько секунд осталось по лицензии
function getSecondsWork(startDate, endDate){//, endDate){
// startDate - это дата которую мы получили от клиента
// endDate - эту дату мы берем из таблицы
return (startDate - new Date(Date.parse(endDate)))/1000;
}
String.prototype.MD5 = function(charset, toByte) {
charset = charset || Utilities.Charset.UTF_8;
var digest = Utilities.computeDigest(Utilities.DigestAlgorithm.MD5, this, charset);
if(toByte) return digest;
var __ = '';
for (i = 0; i < digest.length; i++) {
var byte = digest[i];
if (byte < 0) byte += 256;
var bStr = byte.toString(16);
if (bStr.length == 1) bStr = '0' + bStr;
__ += bStr;
}
return __;
}
И внесем исправления в код кубика C# всамом шаблоне:
C#:
JavaScriptSerializer ser = new JavaScriptSerializer();
//Где опубликован скрипт
string licUrl = "вставьСвойУрлСкрипта";
//Параметры полученые шаблоном
string mail = Microsoft.Win32.Registry.CurrentUser.OpenSubKey("SOFTWARE\\ZennoLab").GetValue("login").ToString();
string date = DateTime.UtcNow.ToString("s")+"Z";
//Форматируем параметры
string parameter = string.Format("?mail={0}&date={1}&HASH={2}", mail, date, Convert.ToString(mail + project.Name).GetMD5Hash());
//отправляем запрос
string response = ZennoPoster.HttpGet(licUrl + parameter, "", "UTF-8", InterfacesLibrary.Enums.Http.ResponceType.BodyOnly);
project.SendInfoToLog(response);
//Сделаем словарь из ответа нашего гугл скрипта
Dictionary<string, dynamic> d = ser.Deserialize<Dictionary<string, dynamic>>(response);
//проверем чтобы мы нашли клиента 100%
if(d.ContainsKey("error")){//Если не нашли клиента
ZennoPoster.StopTask(Guid.Parse(project.TaskId)); // остановим выполнение шаблона
throw new Exception(d["error"] + " Oбратитесь в телеграм к разработчику @zhagru");
}
//расчитываем количество секунд оставшихся до конца лицензии
TimeSpan t = DateTime.Parse(d["ExpiredDate"]) - DateTime.Parse(date);
int i = (int)t.TotalMilliseconds/1000; // проверим что еще есть время для работы, если тут получим отрицательное число, то лицензия кончилась
//проверяем можно работать или нет
if(i<0) throw new Exception(d["ExpiredDate"] + " закончилась лицензия");
string salt = "сольМоя"; // это секретное слово которое должно совпадать с секретным словом в гугл скрипте
project.SendInfoToLog(Convert.ToString(salt + i.ToString()).GetMD5Hash());
if(d["s"] == salt.GetMD5Hash() + i.ToString().GetMD5Hash()){//сверим хеши
return "";
}
else
throw new Exception(d["ExpiredDate"] + " закончилась лицензия");
Вот ребятки такая штука получилась. Шаблон и текст гугло скрипта приложу.
- Номер конкурса статей
- Восьмой конкурс статей
- Тема статьи
- Другое
Вложения
Последнее редактирование:





