• 15 апреля стартует «Курс «SQL-injection Master» ©» от команды The Codeby

    За 3 месяца вы пройдете путь от начальных навыков работы с SQL-запросами к базам данных до продвинутых техник. Научитесь находить уязвимости связанные с базами данных, и внедрять произвольный SQL-код в уязвимые приложения.

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

    Запись на курс до 25 апреля. Получить промодоступ ...

Notesminder-напоминалка О Новых Документах Для Lotus

  • Автор темы morpheus
  • Дата начала
M

morpheus

Доброго всем времени сутокпредлагаю Вашему вниманию простенькую, но для "моих" нужд необходимую программу.<p>ВНИМАНИЕ! Программа обновилась. Актуальная версия 1.0.0.7
  • теперь вы можете использовать программу для нескольких баз данных (XML-файл с настройками).
  • нет необходимости вносить изменения в ваши базы данных - программа может просто проходится по всем документам в виде
  • программа поддерживает @Formula (но НЕ в имени сервера/базы/вида, только в полях относящихся к нотес-документам)
  • добавились всплывающие уведомления (как в ICQ)ю Сообщения автоматически пропадают через 15 сек (можно настроить).
  • теперь вы можете сохранять изменения внесённые в закладках настроек.
<p>Суть: Приблуда каждые ХХХ минут стучится в заранее указанную базу данных Lotus Notes Domino и проверяет наличие для текущего пользователя "новых" документов. Если появилось что-то новое, об этом сообщается "облачком" из системного трея(см. скрины). Новое сообщение
inComing.png
Это, фактически, аналог встроенного minder'а в клиент Notes, с той лишь разницей, что мониторить можно любую доступную базу, проделав для этого минимум дизайнерский ухищрений.<p>Архитектура: Приблуда работает используя domino.tlb версии 6.5.4 ( тестировалась на 7.0.2 и 8.5.х клиентах ), в себе не хранит никаких данных (кроме тех что отображены на экране) и использует текущие настройки пользователя (расположение ИД-файла, подключения к серверу - используются нотес-имена). <p>Требования:Инсталлированный (или зарегистрированный как СОМ-Сервер в реестре Windows ) клиент Нотес, FrameWork 3.5 и выше, предоставление доступа для самого приложения (не всегда). Представление в целевой БД с первой сортировочной колонкой = имя текущего пользователя а также целевые документы должны иметь поле Subject - на основании которого и вычисляется что показать в списке<p>Начало работы и настройка: Для начала работы необходимо разархивировать скачанный архив в отдельную папку и запустить приложение. В закладках "Настройка" указать имя сервера Domino/XXX, путь к базе данных folder\dbname.nsf, а также имя представления MySuperView. С остальным думаю разберётесь.<p>Настройки теперь расширились. Из интерфейса программы можно поменять лишь некоторые параметры, а именно:
  • выводить всплывающие уведомления
  • Время "жизни" всплывающего уведомления
  • сворачивать в трей при открытии уведомления в лотус
Для работы с базами данных используется отдельный XML файл - "dbConfig.xml". В котором, в тегах "DB" указываются подробные настройки как работать с базой: <div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Описание тэгов</div></div><div class="sp-body"><div class="sp-content">
<th>TAG</th> <th>Поддерживаются @формулы</th> <th>Описание</th> <th>Пример</th> server нет Сервер баз данных. имя из лотуса.MyServer/ORG dbpath нет путь к базе данных.FOLDER\itProjects.nsf nview нет наименование вида/папкиvMyView key ДА Ключ для отработки ф-ции GetAllDocumentsByKey. В случае если пусто - обработаются все документы в виде. @UserName urlfield ДА Наименование поля/формула в котором содержится ссылка на документ. В случае если пусто - открывается документ-уведомление. ParentDocumentURL_FIELD interval НЕТ Периодичность обращений к базе даных. размерность минуты 1 field_subject ДА Наименование поля/формула в котором содержится тема документа Subject field_sender ДА Наименование поля/формула в котором содержится отправитель документа From field_date ДА Наименование поля/формула в котором содержится дата документа. Не работает @Created field_name_to_change ДА Наименование поля/формула в которое вносятся изменения в документе уведомлении. Н.: информация о том что документ прочитан readStatus field_value_to_change ДА Значения поля/формула которое вносится в документ уведомление. 1
<p>ВНИМАНИЕ: При написании @Formula будьте внимательны - XML имеет некоторую специфику работы с символам - ковычки, апостроф, тильда, символ ограничивающий теги и т.д. - описываются . Пример правильной записи динамической формулы @middle есть в архиве!<p>Ввод пароля ( средствами нотес, приблуда об этом вообще ничего "не знает" )
Password.JPG
Пасмотрим что тут у нас
Messages.JPG
Сама программка<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Старая версия</div></div><div class="sp-body"><div class="sp-content">З.Ы. В принципе ничего не мешает доделать опцию запоминания пароля, но я специально не делал этого, т.к. не располагаю достаточными знаниями в криптовании, и не уверен что смогу достойно защитить пароли ( пока что ).
 

Вложения

  • Tray.JPG
    Tray.JPG
    9,1 КБ · Просмотры: 1 253
M

morpheus

Вот, добрался.

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

  1. Создаём Windows Forms Application.
  2. Добавить библиотеку типов - domino.tlb. Для этого в меню Project\Add Reference где в проводнике и находим нужную библиотеку (ищите в месте установке клиента Lotus Notes). Visual Studio сам создаст "обёртку" к данной библиотеке и Вы сможете использовать "родные" для Вас notes-классы.
  3. Я для себя определил следующюю схему:объявляю глобальную переменную нотес-сессии(Domino.NotesSession nsSession), по желанию пользователя инициирую, а сбор данных веду в отдельном потоке.
  4. Для сбора данных в отдельном потоке использую отдельный самописный клас(ThreadsElements) который "асинхронно" используется в компоненте
  5. Собранные данные скидываю в компоненту , а при необходимости вывожу всплывающее сообщение из системного трея ( компонента ).

Листинг на C# ( Visual Studio 2010 )
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Компоненты - описание</div></div><div class="sp-body"><div class="sp-content">
/*
* imageList1 - компонента, контейнер рисунков(для отображения в сис.трее)
* dtGridMain - компонента-таблица для отображения списка новых сообщений
* backgroundWorker1 - комп.-для работы в отдельном потоке(читать литературу)
* cmsIconMenu - комп.-контекстное меню, для иконки
* btnConnect - кнопка включить
* btnOff - кнопка "свернуть в трей"
* btnClose - кнопка "Выключить и выйти"
* tbCntrlMain -комп.-табуляторный контрол с 2мя закладками ( tabPage1 и tpOptions )
* txtbxServer, txtbxDataBase, txtbxView - комп.-текстбоксы с настройками "куда" смотреть
* comboBox1 - комп.-комбобокс в которой выбираеться временной интервал для запросов
* rbDBlClickChColor, rbDBlClickDelFromGrid - комп.-радобатон для выбора действия при клике на новом сообщении ( менять цвет или удалять из списка)
* chBxHideInTrayOnDblClick - комп.-чекбокс для сворачивания окна программки при открытии ссылки на новое сообщение.
*/

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Обьявление гл.переменных </div></div><div class="sp-body"><div class="sp-content">
C++:
		Domino.NotesSession nsSession; // глобальная переменная, для сессии 
ThreadsElements asyncObj = new ThreadsElements(); // глобальная переменная для работы в потоке, описан ниже
Boolean mClose = false; // для понимания закрыть программу или свернуть

// Константы - номера иконок для сис. трея. обозначает номер рисунка в imageList1
int iOffLine = 0;
int iOnLine = 5;
int iNewMsg = 1;

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Кнопка включить</div></div><div class="sp-body"><div class="sp-content">
C++:
private void btnConnect_Click(object sender, EventArgs e)
{
if (nsSession == null) {
try // создаём сессию
{ nsSession = new Domino.NotesSession(); }
catch (Exception err)
{
MessageBox.Show(err.Message);
}
} 

try // тут может быть ошибка, пользователь отменяет ввод пароля кнопкой Cancel
{ nsSession.Initialize(); } // иницируем, можем сразу передать пароль. например nsSession.Initialize("myPassWord001"); 
catch (Exception err)
{
nsSession = null;
MessageBox.Show(err.Message);

// Включились в офф-лайн вещание
// nicnMain.Icon = Icon.FromHandle(((Bitmap)imageList1.Images[iOffLine]).GetHicon()); // Пока отключено
}

if (nsSession == null)
{ 
nicnMain.ShowBalloonTip(300, "Ошибка", "Подключиться не удалось", ToolTipIcon.Error);
nicnMain.Text = "Авто оповещение [Откл.]";
}
else
{
if ( asyncObj.IsConnected == false ) 
asyncObj = new ThreadsElements() // создаем обьект для работы в отдельном потоке и задаём параметры
{					  
IsConnected = true, 
ServerName = txtbxServer.Text, 
DBName = txtbxDataBase.Text, 
ViewName = txtbxView.Text,
s = nsSession,
iSleep = System.Convert.ToInt32(comboBox1.Text) ,
IsFirstTimeRun = true
};

// Включились в он-лайн вещание
// nicnMain.Icon = Icon.FromHandle(((Bitmap)imageList1.Images[iOnLine]).GetHicon()); // Пока отключено
nicnMain.Text = "Авто оповещение [Bкл.]";

backgroundWorker1.RunWorkerAsync(asyncObj); // начинаем паралельный поток по сбору данных
tbCntrlMain.TabPages["tpOptions"].Enabled = false; // делаем закладку опций неактивной
tbCntrlMain.SelectedTab = tbCntrlMain.TabPages[0]; // переходим на закладку с таблицей
btnConnect.Enabled = false; // Кнопку Включить "дизейблим", чтобы больше не клацали
Hide(); // Скрываем приложение в трей
}
}

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Кнопка - свернуть в трей</div></div><div class="sp-body"><div class="sp-content">
C++:
 private void btnOff_Click(object sender, EventArgs e)
{
Hide();  
}

Компонента backgroundWorker1 имеет два события DoWork (зделать чтотоd отдельном потоке) и RunWorkerCompleted(что сделать по завершении выполнения потока)
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">backgroundWorker1</div></div><div class="sp-body"><div class="sp-content">
C++:
		// дополнительный поток ( для запроса в кабинет )
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
ThreadsElements teTest = e.Argument as ThreadsElements; // берём объект для работы в тек. потоке ( см. синхронизацию переменных в потоках + google )

if (teTest.IsFirstTimeRun == true) // первый раз поток без задержки
{ 
teTest.IsFirstTimeRun = false;
}
else // зделать "задержку" что бы не дёргать базу слишком часто
{
if (teTest.iSleep > 0)
{ 
Thread.Sleep(teTest.iSleep); // исходя из выбранного значения в comboBox1
}
else
{ 
Thread.Sleep(300000); // по умолчанию 5 минут
}
}

if (teTest.s == null)  // Нотес-сессия		
{
try // тут может быть ошибка, пользователь отменяет воод пароля
{ teTest.s.Initialize(); }
catch (Exception err)
{
teTest.s = null;
teTest.IsConnected = false;
MessageBox.Show(err.Message);

// Включились в офф-лайн вещание
// nicnMain.Icon = Icon.FromHandle(((Bitmap)imageList1.Images[iOffLine]).GetHicon());
nicnMain.Text = "Авто оповещение [Откл.]";
}
}

if (teTest.s == null) { nicnMain.ShowBalloonTip(300, "Ошибка", "Подключение потеряно", ToolTipIcon.Info); }
else
{
try
{
Domino.NotesDatabase ndbTest;
Domino.NotesDocument ndTmp;
Domino.NotesDocumentCollection ndColl;
Domino.NotesView nvTest;
NotesMemos nmTmp;
int iNew = 0;

ndbTest = teTest.s.GetDatabase(teTest.ServerName, teTest.DBName, false); // Подключаемся к базе				 
nvTest = ndbTest.GetView(teTest.ViewName); // берём нужный "вид"

ndColl = nvTest.GetAllDocumentsByKey(nsSession.UserName, true); // берём документы по ключу
ndTmp = ndColl.GetFirstDocument(); // берём первый документ

while (ndTmp != null)
{
if (teTest.HasURL(ndTmp.NotesURL.ToString())==false) // а был ли такой документ в нашей коллекции, если небыл то...
{
iNew++;

nmTmp = new NotesMemos(); // доп. клас с описанием отдельно нотес-документа, см.ниже
nmTmp.sNotesURL = ndTmp.NotesURL.ToString(); // Нотес-урл для открытия из таблицы
nmTmp.sCreatedDate = ndTmp.Created.ToString(); // Дата создания документа
nmTmp.sTitle = ndTmp.GetFirstItem("Subject").Text.ToString(); // тема из документ 
// тут можете собрать сколько угодно информации из документа, насколько хватит фантазии

teTest.AllInfo.Add(nmTmp);	 // вносим наш "документ" в list всех документов, см.ниже
}

ndTmp = ndColl.GetNextDocument(ndTmp);
}
}
catch (Exception nErr)
{
nicnMain.ShowBalloonTip(3000, "Подключение потеряно", nErr.Message, ToolTipIcon.Error);
}

e.Result = teTest; // определяем результат выполнения потока
}	 
}

// по окончанию потока, запустить его заново
private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
ThreadsElements teTest = e.Result as ThreadsElements;
int n = 0;
int c = 0;

if (teTest.IsConnected) // проверяем статус подключения
{	 
foreach ( NotesMemos sURL in teTest.AllInfo ) // для всех записей NotesMemos в list-коллекции
{
if (sURL.IsNew) // а новый ли это элемент
{
n = dtGridMain.Rows.Add(); // берём номер новой строки в таблице

dtGridMain.Rows[n].Cells[0].Value = (n+1).ToString(); // порядковый номер
dtGridMain.Rows[n].Cells[1].Value = sURL.sCreatedDate; // дата создания
dtGridMain.Rows[n].Cells[2].Value = sURL.sTitle; // Тема из документа
dtGridMain.Rows[n].Cells[3].Value = sURL.sNotesURL; // ссылка для открытия. Колонка скрыта

c++;
sURL.IsNew = false; // ставим поментку, что документ уже не новый
}
}

if (c > 0) // Есть новые сообщения
{
nicnMain.ShowBalloonTip(3000, "Внимание", "Новых сообщений: " + c.ToString() + " \n" + "Всего " + dtGridMain.Rows.Count.ToString(), ToolTipIcon.Info);
nicnMain.Text = "У Вас новых/всего сообщений " + c.ToString() + " / " + dtGridMain.Rows.Count.ToString() + "";

// Включились в офф-лайн вещание
// nicnMain.Icon = Icon.FromHandle(((Bitmap)imageList1.Images[iNewMsg]).GetHicon());
}
}
else
{
asyncObj = new ThreadsElements()
{
IsConnected = true,
ServerName = txtbxServer.Text,
DBName = txtbxDataBase.Text,
ViewName = txtbxView.Text,
iSleep = System.Convert.ToInt32(comboBox1.Text),
s = nsSession
};
}


backgroundWorker1.RunWorkerAsync(asyncObj);
}

И так, таблицу наполнили, запросы идут, уведомление из трея вылазит.
Осталось дорисовать открытия документа по двойному клику из ДатаГрид'a
<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Двойной клик по записи в таблице</div></div><div class="sp-body"><div class="sp-content">
C++:
 // Управление открытием ссылок
private void dtGridMain_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{
int n = e.RowIndex;

try
{
System.Diagnostics.Process.Start(dtGridMain.Rows[n].Cells["NURL"].Value.ToString()); // открываем notesUrl
dtGridMain.ClearSelection(); // убираем выделение в таблице

// при открытии свернуть в трей
if (chBxHideInTrayOnDblClick.Checked)
Hide();

if (rbDBlClickChColor.Checked) // просто поменять цвет при открытии из таблицы
{
for (int i = 0; i <= dtGridMain.Rows[e.RowIndex].Cells.Count; i++)
{
dtGridMain.Rows[e.RowIndex].Cells[i].Style.BackColor = Color.LightGray;
}
}
else // удалить строку при открытии из таблицы
{
nicnMain.Text = "У Вас всего сообщений " + dtGridMain.Rows.Count.ToString();				
dtGridMain.Rows.Remove(dtGridMain.Rows[e.RowIndex]);
}
}
catch { }
}

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">При закрытии - свернуть в трей</div></div><div class="sp-body"><div class="sp-content">
C++:
 // При закрытии свернуть в трей
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (e.CloseReason != CloseReason.TaskManagerClosing &&
e.CloseReason != CloseReason.WindowsShutDown && mClose != true)			 
e.Cancel = true;			
this.WindowState = FormWindowState.Minimized;
Hide();
}

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">Класс для работы в паралельном потоке</div></div><div class="sp-body"><div class="sp-content">
C++:
	public class ThreadsElements
{
// Properties public
public Boolean IsConnected = false; // индикатор подключения
public Domino.NotesSession s = null; // обьект - сессия
public String ServerName = ""; // имя сервера
public String DBName = ""; // путь к базе
public String ViewName = ""; // имя предаствления
public Boolean IsFirstTimeRun = false; // запущенно первый раз
public List<NotesMemos> AllInfo = new List<NotesMemos>(); // List(список) NotesMemos(см.ниже) записей
public int iSleep // = 300000; // каждые пять минут // задержка
{
get 
{
return iMlSSlep;
}
set 
{
if (value > 0)
{
iMlSSlep = value * 1000 * 60; // минуты в миллисекунды ... приблизительно
}
else
{
iMlSSlep = 300000;
}
}
}

// Properties private
private int iMlSSlep = 300000;

// Functions and Methods		
public Boolean HasURL ( String sURL ) // Проверка на наличии в коллекции найденного документа
{

if (AllInfo.Count > 0)
{
foreach (NotesMemos k in AllInfo)
{
if (k.sNotesURL.Equals(sURL)) return true;
}
}

return false;
}

}

<div class="sp-wrap"><div class="sp-head-wrap"><div class="sp-head folded clickable">NotesMemos - класс для описания нотес-документа</div></div><div class="sp-body"><div class="sp-content">
C++:
public class NotesMemos 
{
public String sNotesURL = ""; // ссылка на документ
public String sCreatedDate = ""; // дата создания
public String sTitle = ""; // тема
public Boolean IsNew = true; // новенький
}
 
S

shproteg

А реально чтобы данная программа работала без установленного клиента Lotus Notes?
 
M

morpheus

shproteg
не думаю, хотя когда то видел тему про "урезаного клиента" ... но не понимаю зачем это, без лотуса сама программка теряет всякий смысл
 
S

shproteg

Смысл в том что есть еще "тонкие" вэб клиенты а оповещалки у них нет вот и хотелось бы "независимую" оповещалку найти
 
M

morpheus

shproteg
если веб - клиенты то оповещалку просто разместить на веб-морде - тут вам ajax в помощь
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
А можно ли выводить пароль не в COM-окне, а в OLE, как это делает сам клиент? Задача в том, чтобы выбрать нужный Location, а не пользовать данные из notes.ini последнего пользователя, заходившего в клиент.

И вообще бомба была бы, если на указанное количество секунд выводить не просто уведомление "новых столько-то", а выводить перечень уведомлений, и при щелчке на любом открывать сам док в Лотусе (OLE-то ведь инициализирован при вводе пароля).
Ну и для писем выводить имя отправителя и тему.

Ещё дать возможность натравливать на несколько баз, а во всплывающем окошке выводить:
Почта: Re: test (Х-ков Сидор П.-вич)
Документы: Док №ххх (Бухгалтерова Бухгалтерка Бухгалтеровна)
 
M

morpheus

А можно ли выводить пароль не в COM-окне, а в OLE, как это делает сам клиент?
- это наврят


Задача в том, чтобы выбрать нужный Location, а не пользовать данные из notes.ini последнего пользователя, заходившего в клиент.
- думаю список Location както можно будет выдернуть

И вообще бомба была бы, если на указанное количество секунд выводить не просто уведомление "новых столько-то", а выводить перечень уведомлений, и при щелчке на любом открывать сам док в Лотусе (OLE-то ведь инициализирован при вводе пароля).
Ну и для писем выводить имя отправителя и тему.
можно

Ещё дать возможность натравливать на несколько баз, а во всплывающем окошке выводить:
- думаю тоже можно будет допилить
 
M

morpheus

ВНИМАНИЕ программа обновилась
 

VladSh

начинающий
Lotus Team
11.12.2009
1 784
157
BIT
57
Пытаюсь скачать и не могу, - последний NOD говорит, что "Потенциальная угроза" и не даёт. Опция "Отключить защиту от вирусных и шпионских программ" не помогает. Как-нибудь можно обойти (вырубить антивирус не могу - политики)? Можно передать файл на проверку туда, тогда они через пару дней исключат из списка угроз.
 

seoman2

Green Team
17.02.2010
504
1
BIT
45
А как сделать, чтобы не надо было вводить пароль от ид при запуске?
Программк не всегда выходит из трея.
 
M

morpheus

А как сделать, чтобы не надо было вводить пароль от ид при запуске?
Я не смогу обеспечить "безопасноть" такого пароля, т.к. прийдёться хранить его в открытом виде (ну или в очень "легко" зашифрованном).

Программк не всегда выходит из трея.
Есть такое, "отловить" не получается ((
 
Мы в соцсетях:

Обучение наступательной кибербезопасности в игровой форме. Начать игру!