• Codeby web-security - Курс "Тестирование Веб-Приложений на проникновение с нуля" от команды codeby. Общая теория, подготовка рабочего окружения, пассивный фазинг и фингерпринт, Активный фаззинг, Уязвимости, Пост-эксплуатация, Инструментальные средства, Social Engeneering и многое другое. Подробнее ...

  • Мобильный клиент нашего форума для Android гаджетов доступен в Google Play Market по этой ссылке. Клиент можно скачать с нашего форума по этой ссылке. Последняя версия МК в нашем телеграм канале вот здесь

Унификация разработки

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 689
305
#1
Речь пойдет больше про java и xpages
Что хочется:
- писать код и тестировать его во внешних ИДЕ (дизайнер сильно убогий по разработке java/js...)
- при переносе в дизайнер минимально изменять код
- кроссплатформа

про Team Development знают (полагаю) все, там есть ODP (On Disk Project) т.е. создавая приложение можно ему назначить его отображение на папку, а уже её синхронить и с nsf и с git (как вариант)
Засада состоит в том, что классы домины привязаны к нативным либам, что создает массу нецдобств и отсутствие переносимости (если рарабаывать одновременно в дизайнере и ИДЕ, на др. платформе)

Вариант с IIOP ну очень горбатый. Предлагаю следующую модель:
- пишем REST для доступа в сущностям, возможно использовать
Для просмотра контента необходимо: Войти или зарегистрироваться

- делаем финт с авторизацией (уже описывал) - создавая LtpaToken, через страницу в публичным доступом и шифрованием
- обращение к сущностям получаем в виде JSON
- к внешней ИДЕ надо будет прикрутить
Для просмотра контента необходимо: Войти или зарегистрироваться
(в домине оно и так есть)
немного кода xAgent_token.xsp:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core" rendered="false">
    <xp:this.beforePageLoad><![CDATA[#{javascript:try {
var url = context.getUrl();
var host = url.getHost();
var domain=host.match(/\..*/)[0];
var response=facesContext.getExternalContext().getResponse();

//var token=paramValues.get("token").toString();
//var rUrl=paramValues.get("url").toString();
var user_enc = context.getUrlParameter('id');
print("::xAgent_token::id:" + user_enc);
var user=decrypt(base64_decode(user_enc));
print("::xAgent_token::User:" + user);
/* var httpURL = database.getHttpURL();
var dbUrl= httpURL.replace("http://", "https://").match(/(.+)\?/)[1];
print("url:"+dbUrl);
*/
  var generated=LtpaGenerator(user);

//var header="LtpaToken=" + token + "; domain=" + domain + "; path=/";

//response.setHeader("Set-Cookie", header);
//facesContext.getExternalContext().redirect(rUrl);
  var externalContext:javax.faces.context.ExternalContext = facesContext.getExternalContext();
  var response:javax.servlet.http.HttpServletResponse = externalContext.getResponse();
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", -1);
  var externalContext:javax.faces.context.ExternalContext = facesContext.getExternalContext();
  var response:javax.servlet.http.HttpServletResponse = externalContext.getResponse();
  response.setHeader("Cache-Control", "no-cache");
  response.setDateHeader("Expires", -1);
  var gVars=getVars();
  print("::xAgent_token::token:"+generated);
  response.setHeader("Set-Cookie", "LtpaToken=" + generated + "; domain="+ gVars.domain + "path=/");
  //response.setContentType("text/html;charset=UTF-8");
  var writer:java.io.PrintWriter = response.getWriter();
  writer.write(generated);

} catch(e) {
        _dump(e);
}
}]]></xp:this.beforePageLoad>

    <xp:this.resources>
        <xp:script src="/SSJSUtils.jss" clientSide="false"></xp:script>
    </xp:this.resources>
</xp:view>
либы уже выкладывал, если нужно что-то довыложить - спрашивайте
суть проста - генерим токен при вызове страницы, ответом прописываем куки на запрашивающую сторону
следом можем уже вызывать REST или DAS
Java:
import com.ibm.commons.util.io.json.JsonException;
import com.ibm.commons.util.io.json.JsonJavaFactory;
import com.ibm.commons.util.io.json.JsonParser;
import org.apache.commons.codec.binary.Base64;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;

public class DAS {
    //... здесь поля, кот. зависят от приложения target - это адрес "...xAgent_token.xsp?id=" + encBase64 (см. authorize)
    private static final JWT jwt = new JWT();
    private static final String encrypted = jwt.encrypt(userName,key);
    private static final String encBase64=new String(Base64.encodeBase64(encrypted.getBytes()));
    static{TrustAllCertificates.install();}

    private static List<String> cookies;

    public static InputStream request2URL(String target) throws IOException {

        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        InputStream res = null;
        if (conn.getResponseCode() == 200) {
            System.out.println("OK");
            res= conn.getInputStream();
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
            if (cookies!=null) {
                for (String el : cookies) {
                    System.out.println(el);
                }
            }

        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }
    public static String request2URLString(String target) throws IOException {
        String res="";
        URL url=new URL(target);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (cookies!=null)
            for (String cookie : cookies) {
                conn.addRequestProperty("Cookie", cookie.split(";", 2)[0]);
            }

        if (conn.getResponseCode() == 200) {
            System.out.println("OK");
            res= result2String(conn);
            if (cookies==null)cookies = conn.getHeaderFields().get("Set-Cookie");
            if (cookies!=null) {
                for (String el : cookies) {
                    System.out.println(el);
                }
            }

        }else{
            System.out.format("Request status %d -> %s\n",conn.getResponseCode(),conn.getResponseMessage());
        }
        return res;
    }

    private static String result2String(HttpURLConnection conn) throws IOException {
        StringBuilder res = new StringBuilder();
        BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
        String line = "";
        while ((line = reader.readLine()) != null) {
            System.out.println(line);
            res.append(line);
        }
        reader.close();
        return res.toString();
    }

    public static void authorize() throws IOException {
        cookies=null;
        URL url=new URL(target+encBase64);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection();
        if (conn.getResponseCode() == 200) {
            result2String(conn);
            cookies = conn.getHeaderFields().get("Set-Cookie");
            for (String el : cookies) {
                System.out.println(el);
            }
        }
    }
    //https://stackoverflow.com/questions/40917681/in-xpages-how-do-you-get-the-post-body-from-a-rest-call
    //jar: https://jar-download.com/?detail_search=g%3A%22com.ibm.sbt%22+AND+a%3A%22com.ibm.commons%22+AND+v%3A%229.0.0%22&a=com.ibm.commons
    public static void main(String[] args) throws IOException, JsonException {
        authorize();
        //String res=request2URLString(serverURL+dbPart+"/PDFTemplates"+viewJsonPart);
        String reqnames=request2URLString(serverURL+dbPart+"/restCustom.xsp/customJSONcat");
        List<Map<String, Object>> names = (List<Map<String, Object>>)JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);;
        for(Map<String, Object> nameobj:names) {
            String nameconf = (String) nameobj.get("name");
            String req = request2URLString(serverURL + dbPart + "/restCustom.xsp/customJSONfilter?key="+nameconf);
            System.out.print("*********** "+nameconf+" ");
            //"https://mail1.castrolcis.com/templates/qpassport.nsf/restCustom.xsp/customJSONfilter?key=Neuhof,France"
            //InputStreamReader isR = new InputStreamReader(request2URL(serverURL+dbPart+"/restCustom.xsp/customJSONfilter?key=Neuhof,France"));
            //JsonJavaObject jsonObj = (JsonJavaObject) JsonParser.fromJson(JsonJavaFactory.instanceEx, isR);
            //List<Map<String, Object>> arr
            List<Map<String, Object>> result = (List<Map<String, Object>>) JsonParser.fromJson(JsonJavaFactory.instanceEx, req);
            for (Map<String, Object> map : result) {
                String rowmap = (String) map.get("rowmap");
                String name = (String) map.get("name");
                String region = (String) map.get("region");
                boolean isID = (Boolean) map.get("isID");
                System.out.format("********************\nname:%s\nregion:%s\nrowmap:\n", name, region);
                new PDFDBReadConfig.TestTable(region, isID, rowmap.split(";"));
                for (String r : rowmap.split(";")) {
                    System.out.format("\t%s\n", r);
                }
            }
        }
    }
}
ключ (key)для шифрования используется при отправке имени пользователя, он должен соответствовать таковому на сервере. Json парсер - это как-раз из com.ibm.commons.util.io.json
в main вызывается autorize() и после - запрос к домине (токен передается с куками)
В домине будет использован тот же JSON хоть из java хоть из JS
Т.е. формат и логика разработки будут одинаковы в ИДЕ и дизайнере
 
Последнее редактирование:

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 689
305
#2
еще момент - есть получение данных из вьюшки типа формата JSON
ниже кусок получения значений из вьюшки с отображением мультивэлью как несколько строк
Java:
private static final String viewJsonPart="?ReadViewEntries&OutputFormat=JSON";
....
        String reqnames=request2URLString(serverURL+dbPart+"/"+TMPL_VIEW+viewJsonPart);
        Map<String, Object> viewmap = (Map<String, Object>) JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);
        List<JsonObject> entries= (List<JsonObject>) viewmap.get("viewentry");
        //List<Map<String, Object>> names = (List<Map<String, Object>>)JsonParser.fromJson(JsonJavaFactory.instanceEx, reqnames);
        for(JsonObject entry:entries) {
            System.out.println(entry.getJsonProperty("entrydata"));// +"\n"+ entry.getJsonProperty("entrydata").getClass().getName());
            List<JsonObject>list= (List<JsonObject>) entry.getJsonProperty("entrydata");
            System.out.println(list.get(0).getJsonProperty("text"));
            JsonObject jo=(JsonObject)list.get(2).getJsonProperty("textlist");
            if (jo!=null) {
                List<JsonJavaObject> arrJsonJavaObject = (List<JsonJavaObject>) jo.getJsonProperty("text");
                System.out.println(arrJsonJavaObject.get(0).get("0"));
/*
                //only one element
                for (JsonJavaObject jjo : arrJsonJavaObject) {
                    System.out.println(StringEscapeUtils.unescapeJava(jjo.toString()));
                }
*/
 
Последнее редактирование:

savl

Lotus team
28.10.2011
2 138
105
#3
@lmike а автосборку еще не рассматривал? Я вот смотрю в эту сторону, причем для классики...
есть такое:
Для просмотра контента необходимо: Войти или зарегистрироваться

Я даже просто пробовал делать командами через батник, но операция пока полуручная... И надо многое продумать...
Там еще был проект с участием Ant сборщика.
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 689
305
#4
Я вот смотрю в эту сторону, причем для классики...
пока нет и меня смущает необходимость нативных либ домины
по ссылке - это что-то экстримальное ;) - патч на класс
цель моих изысканий - получение рабочего варианта (без нотусевых сущностей), кот. я почти 1-1 перенесу в домину, и для теста нужен только доступный сервер домины
по сути этот подход очень напоминает ODA, но нет необходимости в доп. OSGi плаге на сервере
в тек. состоянии я уже спокойно обращаюсь БД, через http, на домине будет также. Накладные расходы будут нивелированы отсут. recycle для нотусевых объектов и необходимости их перетаскивания в память и "обратно"...
 
Последнее редактирование:

savl

Lotus team
28.10.2011
2 138
105
#6
ну это я как вариант, а вот автосборку можно запустить и простой командой. Но для этого нужен дизайнер где-то, да еще и старт без запроса пароля... а значит винда, которую ты не перевариваешь...
в целом, идея то хорошая, мне самому надо сделать что-то вроде CI/CD для Domino, да еще и с контролем версий.
Но на DAS + Web + xpage я даже не надеюсь, в компаниях с большим уровнем иерархии такие идеи просто застревают :(
 

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 689
305
#7
Но для этого нужен дизайнер где-то, да еще и старт без запроса пароля... а значит винда, которую ты не перевариваешь...
не то чтобы не перевариваю, она реально пропихивается везде, хотя присутствуют сложности в управлении и настройке, особенно для разработки
пример
Для просмотра контента необходимо: Войти или зарегистрироваться

хватануть это можно на ровном месте и подобное задалбывает... я не осущ. подобных масштабов разработок (даже близко) , но куча тупок и ненужной мне активности, винды, мешает сильно
Инструменты - я легко разверну ч-л, от виртуалки до контейнеров, в винде с этим все плохо (куча кастылей и стороннего софта)
CI/CD для Domino, да еще и с контролем версий.
очень близко и разаботку вести в сторонней ИДЕ (я в Idea делаю), сборку в nsf - придется дизайнер дергать...
Но на DAS + Web + xpage я даже не надеюсь
собрать простую демонстрацию и показать начальству, может подействует ;)
сделать демку из моего поста про интеграцию с ОнлиОфис - наглядное совместное редактирование доков (из домины)...
 

savl

Lotus team
28.10.2011
2 138
105
#9
@lmike да. Только по факту, это дизайнер на сервере просто.
То есть ставишь клиент на сервер и через командную строку на сервере запускаешь.
Нашел пару минусов:
1. Клиент на сервере должен запускаться без пароля, это важно.
2. Результирующий проект nsf/ntf кладется в папку Data клиента, всегда в корень !!!11 никаких вложенных папок.
3. Если файл nsf/ntf уже такой есть, то задача не отрабатывает.
4. Логи гавно, без комментариев.
5. Массовый билд не работает, либо я не смог его нормально запустить. Лучше на один проект - один файл и в цикле делать.
6. Имя шаблона для базы не задать... То есть Replace/Refresh потом делать все равно вручную.

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

lmike

нет, пердело совершенство
Lotus team
27.08.2008
6 689
305
#10
натолкнулся на свой же сервак, кот. принимает ssl DH 2048...
для обывательской jvm 1.6 это непреодолимый барьер
а вот jvm домины (у меня IBM Domino (r) Server (Release 9.0.1FP7 for UNIX) кушает это нормально (ИБМ, видать, запилило поддержку, учитывая расширенную поддержку от оракла)
сообщение из Idea при jvm 1.6 такое
javax.net.ssl.SSLException: java.lang.RuntimeException: Could not generate DH keypair
переключение на 1.8 лечит, но не утешает, т.к. хотелосьбы тестировать для "одинаковых" условий
 
Вверх Снизу