• Познакомьтесь с пентестом веб-приложений на практике в нашем новом бесплатном курсе

    «Анализ защищенности веб-приложений»

    🔥 Записаться бесплатно!

  • CTF с учебными материалами Codeby Games

    Обучение кибербезопасности в игровой форме. Более 200 заданий по Active Directory, OSINT, PWN, Веб, Стеганографии, Реверс-инжинирингу, Форензике и Криптографии. Школа CTF с бесплатными курсами по всем категориям.

@GetProfileField для WEB и как правильно

NetWood

Lotus Team
17.04.2008
545
93
BIT
8
Наверное, я повторюсь, но лучше один раз записать...

1. Если Вы взялись разрабатывать сайт на Domino, нужно помнить, что конструкция @GetProfileField на вебе люто кешируется задачей HTTP.
Поэтому, если уже совсем нужно что-то быстро достать из профильного дока без кеша для WEB, нужно использовать конструкцию вида
@GetDocField(@GetProfileField("Configuration_Profile"; "ProfileID"); "WebText"). где ProfileID :=@Text(@DocumentUniqueID) того самого профиля.

2. Кроме того, что профиль кешируется, он может быть разным на каждой реплике базы. Репликация копирует изменение структуры профиля, но не его содержимое полей.
На каждой реплике профиль должен быть пересохранен отдельно. Это такая диковинная фишка от индусов.
Поэтому, на самом начальном этапе разработки нужно понять, какие WEB данные будут специфичны конкретной реплике, а какие общими.
Я бы даже сказал, что для настроек веба профильдок лучше не использовать вообще.
Для этого подойдет отдельный и единственный док в представлени Admin для хранения всяких настроек, а вот стучаться к нему лучше через профиль.
Соответственно, в Configuration_Profile пишем один раз вычисляемое при создании:
DBID :=@Implode(@Subset(@DbColumn("":""; ""; "(Admin)";1);1 ) ), где в первой колонке @Text(@DocumentUniqueID) админ дока.

Для веба достаем из настроечного админ дока данные вот так:
DBID :=@GetProfileField("Configuration_Profile"; "DBID");
AdminEmail :=@GetDocField(DBID; "EmailFrom");
Это работает быстро без всякого кеша, лукапа и на всех репликах будет одинаковым.

В агенте пишем вот так
Set profile = db.GetProfileDocument("Configuration_Profile")
If profile Is Nothing Then Goto ErrorHandler

Set admindoc = DatabaseGetDocumentByUnid (db, profile.DBID(0))
If admindoc Is Nothing Then
ErrorCode = "AdminDoc Is Nothing"
Goto ErrorHandler
End If

где
Код:
''################################################
'Set doc = db.Getdocumentbyunid(unid$)
'If doc Is Nothing Then
' ' Do something
'Else
' ' Do something
'End If

'This is actually an incorrect way of implementing the GetDocumentByUnid in LotusScript. When the GetDocumentByUnid method doesn't find a Lotus Notes document, it gives an error message.
'Also, if used improperly, it may return an irrelevant "ghost" Lotus Notes document, also known as a deletion stub.
'Use this LotusScript function instead to correctly and safely return a relevant Lotus Notes document (or nothing, if there isn't one):

''If DatabaseGetDocumentByUnid.Size = 0 Or DatabaseGetDocumentByUnid.UniversalID = "" Or DatabaseGetDocumentByUnid.IsDeleted Or (Not DatabaseGetDocumentByUnid.IsValid) Then
''     Set DatabaseGetDocumentByUnid = Nothing
''     Exit Function
''End If
''################################################

Function DatabaseGetDocumentByUnid (db As NotesDatabase, unid$) As NotesDocument
    On Error Goto ErrorHandler

    Set DatabaseGetDocumentByUnid = Nothing
    Set DatabaseGetDocumentByUnid = db.GetDocumentByUnid(unid$)

    If DatabaseGetDocumentByUnid Is Nothing Then
        Set DatabaseGetDocumentByUnid = Nothing
    Else
        If DatabaseGetDocumentByUnid.Size = 0 Or _
        DatabaseGetDocumentByUnid.UniversalID = "" Or _
        DatabaseGetDocumentByUnid.IsDeleted  Then
            Set DatabaseGetDocumentByUnid = Nothing
        End If
    End If
    Exit Function

ErrorHandler:
    If Err = 4091 Then
        If DatabaseGetDocumentByUnid Is Nothing Then
            Set DatabaseGetDocumentByUnid = Nothing
        End If
        Resume Next
    Else
        Resume ExitWithError
    End If

ExitWithError:

End Function

3. На формах базы делаем общую подформу CommonFields с полем DBID для удобного доступа отовсюду, приблизительно, вот так
1607813723526.png

В этой подформе также DBID :=@GetProfileField("Configuration_Profile"; "DBID"); содержит ID административного дока без DbLookup.
Соответственно, на некоторых формах получаем вместо толпы лукапов простые конструкции типа @GetDocField(DBID; "AdminProfileSummary").
В случае рецидивов, можно сделать в админ доке одно поле с содержимым всех полей, которое потом распарсивать, например, через @GetMembers.
 
Последнее редактирование:
Мы в соцсетях:

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